source: main/waeup.aaue/trunk/src/waeup/aaue/students/tests/test_browser.py @ 14118

Last change on this file since 14118 was 14116, checked in by Henrik Bettermann, 8 years ago

Adjust tests.

  • Property svn:keywords set to Id
File size: 40.9 KB
Line 
1## $Id: test_browser.py 14116 2016-08-23 09:03:03Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import os
19import shutil
20import tempfile
21import pytz
22import grok
23from StringIO import StringIO
24from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
25from zope.securitypolicy.interfaces import IPrincipalRoleManager
26from datetime import datetime, timedelta, date
27from mechanize import LinkNotFoundError
28from hurry.workflow.interfaces import IWorkflowState
29from zope.event import notify
30from zope.component.hooks import setSite, clearSite
31from zope.component import getUtility, createObject, queryUtility
32from zope.catalog.interfaces import ICatalog
33from waeup.kofa.app import University
34from waeup.kofa.interfaces import VALIDATED
35from waeup.kofa.students.tests.test_browser import StudentsFullSetup
36from waeup.kofa.students.accommodation import BedTicket
37from waeup.kofa.testing import FunctionalTestCase
38from waeup.kofa.authentication import LocalRoleSetEvent
39from waeup.kofa.browser.tests.test_pdf import samples_dir
40from waeup.aaue.testing import FunctionalLayer
41
42SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
43
44
45class StudentProcessorTest(FunctionalTestCase):
46    """Perform some batching tests.
47    """
48
49    layer = FunctionalLayer
50
51    def setUp(self):
52        super(StudentProcessorTest, self).setUp()
53        # Setup a sample site for each test
54        app = University()
55        self.dc_root = tempfile.mkdtemp()
56        app['datacenter'].setStoragePath(self.dc_root)
57
58        # Prepopulate the ZODB...
59        self.getRootFolder()['app'] = app
60        # we add the site immediately after creation to the
61        # ZODB. Catalogs and other local utilities are not setup
62        # before that step.
63        self.app = self.getRootFolder()['app']
64        # Set site here. Some of the following setup code might need
65        # to access grok.getSite() and should get our new app then
66        setSite(app)
67
68
69    def tearDown(self):
70        super(StudentProcessorTest, self).tearDown()
71        shutil.rmtree(self.workdir)
72        shutil.rmtree(self.dc_root)
73        clearSite()
74        return
75
76UPLOAD_CSV_TEMPLATE = (
77    'matric_number,student_id,display_fullname,level,code,level_session,'
78    'score,ca\r\n'
79    '234,E1000000,Anna Tester,100,COURSE1,2004,%s,%s\r\n')
80
81class OfficerUITests(StudentsFullSetup):
82    # Tests for Student class views and pages
83
84    layer = FunctionalLayer
85
86    def login_as_lecturer(self):
87        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
88        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
89        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
90        # Add course ticket
91        studylevel = createObject(u'waeup.StudentStudyLevel')
92        studylevel.level = 100
93        studylevel.level_session = 2004
94        self.student['studycourse'].addStudentStudyLevel(
95            self.certificate, studylevel)
96        # Assign local Lecturer role for a certificate.
97        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
98        prmlocal = IPrincipalRoleManager(course)
99        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
100        notify(LocalRoleSetEvent(
101            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
102        # Login as lecturer.
103        self.browser.open(self.login_path)
104        self.browser.getControl(name="form.login").value = 'mrslecturer'
105        self.browser.getControl(
106            name="form.password").value = 'mrslecturersecret'
107        self.browser.getControl("Login").click()
108        # Store reused urls/paths
109        self.course_url = (
110            'http://localhost/app/faculties/fac1/dep1/courses/COURSE1')
111        self.edit_scores_url = '%s/edit_scores' % self.course_url
112        # Set standard parameters
113        self.app['configuration'].current_academic_session = 2004
114        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
115        IWorkflowState(self.student).setState(VALIDATED)
116
117
118    def test_gpa_calculation(self):
119        studylevel = createObject(u'waeup.StudentStudyLevel')
120        studylevel.level = 100
121        studylevel.level_session = 2005
122        self.student['studycourse'].entry_mode = 'ug_ft'
123        self.student['studycourse'].addStudentStudyLevel(
124            self.certificate, studylevel)
125        # First course has been added automatically.
126        # Set score.
127        studylevel['COURSE1'].score = 35
128        studylevel['COURSE1'].ca = 20
129        # GPA is 3.0.
130        self.assertEqual(studylevel.gpa_params[0], 3.0)
131        courseticket = createObject('waeup.CourseTicket')
132        courseticket.code = 'ANYCODE'
133        courseticket.title = u'Any TITLE'
134        courseticket.credits = 13
135        courseticket.score = 44
136        courseticket.ca = 22
137        courseticket.semester = 1
138        courseticket.dcode = u'ANYDCODE'
139        courseticket.fcode = u'ANYFCODE'
140        studylevel['COURSE2'] = courseticket
141        # total credits
142        self.assertEqual(self.student['studycourse']['100'].gpa_params[1], 23)
143        # weigheted credits = 3 * 10 + 4 * 13
144        self.assertEqual(self.student['studycourse']['100'].gpa_params[2], 82.0)
145        # sgpa = 82 / 23
146        self.assertEqual(self.student['studycourse']['100'].gpa_params[0], 3.565)
147        return
148
149    def test_grade_weight(self):
150        studylevel = createObject(u'waeup.StudentStudyLevel')
151        studylevel.level = 100
152        studylevel.level_session = 2005
153        self.student['studycourse'].entry_mode = 'ug_ft'
154        self.student['studycourse'].addStudentStudyLevel(
155            self.certificate, studylevel)
156        studylevel['COURSE1'].score = 42
157        studylevel['COURSE1'].ca = 0
158        courseticket = createObject('waeup.CourseTicket')
159        self.assertEqual(studylevel['COURSE1'].weight, 1)
160        self.assertEqual(studylevel['COURSE1'].grade, 'E')
161        self.student['studycourse'].entry_session = 2015
162        self.assertEqual(studylevel['COURSE1'].weight, 0)
163        self.assertEqual(studylevel['COURSE1'].grade, 'F')
164        studylevel['COURSE1'].score = 45
165        self.assertEqual(studylevel['COURSE1'].weight, 2)
166        self.assertEqual(studylevel['COURSE1'].grade, 'D')
167        return
168
169    def test_manage_payments(self):
170        # Add missing configuration data
171        self.app['configuration']['2004'].gown_fee = 150.0
172        self.app['configuration']['2004'].transfer_fee = 90.0
173        self.app['configuration']['2004'].booking_fee = 150.0
174        self.app['configuration']['2004'].maint_fee = 180.0
175        self.app['configuration']['2004'].late_fee = 80.0
176
177        # Managers can add online payment tickets
178        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
179        self.browser.open(self.payments_path)
180        self.browser.getLink("Add current session payment ticket").click()
181        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
182        self.browser.getControl("Create ticket").click()
183        self.assertMatches('...Wrong state...',
184                           self.browser.contents)
185        IWorkflowState(self.student).setState('cleared')
186        self.browser.open(self.payments_path + '/addop')
187        self.browser.getControl("Create ticket").click()
188        self.assertMatches('...Amount could not be determined...',
189                           self.browser.contents)
190        #self.browser.getControl(name="form.p_category").value = ['schoolfee']
191        # Accepotance fee must be paid first
192        #self.browser.getControl("Create ticket").click()
193        #self.assertMatches('...Please pay acceptance fee first...',
194        #                   self.browser.contents)
195        self.app['configuration']['2004'].clearance_fee = 666.0
196        self.browser.getControl(name="form.p_category").value = ['clearance_incl']
197        self.browser.getControl("Create ticket").click()
198        ctrl = self.browser.getControl(name='val_id')
199        cpt_value = ctrl.options[0]
200        # School fee payment ticket can be added ...
201        self.student['studycourse'].certificate.school_fee_1 = 6666.0
202        self.student.nationality = u'NG'
203        self.browser.open(self.payments_path + '/addop')
204        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
205        self.browser.getControl("Create ticket").click()
206        self.assertMatches('...ticket created...',
207                           self.browser.contents)
208        # ... but not paid through the query_history page.
209        ctrl = self.browser.getControl(name='val_id')
210        sfpt_value = ctrl.options[1]
211        self.student['studycourse'].entry_session = 2013
212        self.browser.open(self.payments_path + '/' + sfpt_value)
213        self.browser.getLink("Query eTranzact History").click()
214        self.assertMatches('...alert-danger">Please pay acceptance fee first...',
215                           self.browser.contents)
216        # If clearance/acceptance fee is paid ...
217        self.student['payments'][cpt_value].approveStudentPayment()
218        self.browser.getLink("Query eTranzact History").click()
219        # ... query_history page is accessible.
220        self.assertMatches(
221            '...<h1 class="kofa-content-label">Requery eTranzact History</h1>...',
222            self.browser.contents)
223        # Managers can open school fee payment slip
224        self.browser.open(self.payments_path + '/' + sfpt_value)
225        self.browser.getLink("Download payment slip").click()
226        self.assertEqual(self.browser.headers['Status'], '200 Ok')
227        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
228        # If school fee ticket is paid, the student is automatically set to
229        # school fee paid...
230        ticket = self.student['payments'][sfpt_value].approveStudentPayment()
231        self.assertEqual(self.student.state, 'school fee paid')
232        # ... no further school fee ticket can be added.
233        self.browser.open(self.payments_path + '/addop')
234        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
235        self.browser.getControl("Create ticket").click()
236        self.assertMatches('...Wrong state...',
237                           self.browser.contents)
238        self.browser.open(self.payments_path + '/addop')
239        self.browser.getControl(name="form.p_category").value = ['late_registration']
240        self.browser.getControl("Create ticket").click()
241        self.assertMatches('...ticket created...',
242                           self.browser.contents)
243        return
244
245    def test_for_instalment_payments(self):
246        self.student['studycourse'].certificate.study_mode = 'ug_pt'
247        self.student['studycourse'].certificate.school_fee_1 = 6666.0
248        self.app['configuration']['2004'].union_fee = 1250.0
249        self.app['configuration']['2004'].welfare_fee = 750.0
250        self.student.nationality = u'NG'
251        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
252        self.browser.open(self.payments_path + '/addop')
253        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
254        self.browser.getControl("Create ticket").click()
255        self.assertTrue(
256            'Part-time students are not allowed' in self.browser.contents)
257        self.student['studycourse'].certificate.study_mode = 'ug_ft'
258        self.browser.open(self.payments_path + '/addop')
259        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
260        self.browser.getControl("Create ticket").click()
261        self.assertTrue(
262            'Wrong state. Only students in state \'cleared\' are allowed to pay by instalments'
263            in self.browser.contents)
264        IWorkflowState(self.student).setState('cleared')
265        self.browser.open(self.payments_path + '/addop')
266        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
267        self.browser.getControl("Create ticket").click()
268        self.assertTrue('ticket created' in self.browser.contents)
269        # We can't add the 2nd instalment ticket because the
270        # first one has not yet been approved.
271        #self.browser.open(self.payments_path + '/addop')
272        #self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
273        #self.browser.getControl("Create ticket").click()
274        #self.assertMatches('...1st school fee instalment has not yet been paid...',
275        #                   self.browser.contents)
276        # Ok, then we approve the first instalment ...
277        self.browser.open(self.payments_path)
278        ctrl = self.browser.getControl(name='val_id')
279        p_id = ctrl.options[0]
280        self.browser.open(self.payments_path + '/' + p_id + '/approve')
281        # ... add the second instalment ...
282        self.browser.open(self.payments_path + '/addop')
283        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
284        self.browser.getControl("Create ticket").click()
285        self.assertTrue('ticket created' in self.browser.contents)
286        # ... approve the second instalment ...
287        ctrl = self.browser.getControl(name='val_id')
288        p_id = ctrl.options[1]
289        self.browser.open(self.payments_path + '/' + p_id + '/approve')
290        self.assertEqual(self.student['payments'].values()[0].p_category, 'schoolfee_1')
291        self.assertEqual(self.student['payments'].values()[1].p_category, 'schoolfee_2')
292        # (6666-250)/2 + 1250 + 750 - 500 + 250
293        self.assertEqual(self.student['payments'].values()[0].amount_auth, 4958.0)
294        # (6666-250)/2 + 250
295        self.assertEqual(self.student['payments'].values()[1].amount_auth, 3458.0)
296        return
297
298    def test_manage_payments_bypass_ac_creation(self):
299        self.student['studycourse'].certificate.school_fee_1 = 6666.0
300        self.student.nationality = u'NG'
301        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
302        self.browser.open(self.payments_path)
303        IWorkflowState(self.student).setState('cleared')
304        self.browser.getLink("Add current session payment ticket").click()
305        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
306        self.browser.getControl("Create ticket").click()
307        ctrl = self.browser.getControl(name='val_id')
308        value = ctrl.options[0]
309        self.browser.getLink(value).click()
310        payment_url = self.browser.url
311        logfile = os.path.join(
312            self.app['datacenter'].storage, 'logs', 'students.log')
313        # The ticket can be found in the payments_catalog
314        cat = queryUtility(ICatalog, name='payments_catalog')
315        results = list(cat.searchResults(p_state=('unpaid', 'unpaid')))
316        self.assertTrue(len(results), 1)
317        self.assertTrue(results[0] is self.student['payments'][value])
318        # Managers can approve the payment
319        self.browser.open(payment_url)
320        self.browser.getLink("Approve payment").click()
321        self.assertMatches('...Payment approved...',
322                          self.browser.contents)
323        # Approval is logged in students.log ...
324        logcontent = open(logfile).read()
325        self.assertTrue(
326            'zope.mgr - students.browser.OnlinePaymentApproveView '
327            '- E1000000 - schoolfee_incl payment approved'
328            in logcontent)
329        # ... and in payments.log
330        logfile = os.path.join(
331            self.app['datacenter'].storage, 'logs', 'payments.log')
332        logcontent = open(logfile).read()
333        self.assertTrue(
334            '"zope.mgr",E1000000,%s,schoolfee_incl,6666.0,AP,,,,,,\n' % value
335            in logcontent)
336        # Student is in state school fee paid, no activation
337        # code was necessary.
338        self.assertEqual(self.student.state, 'school fee paid')
339        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
340        return
341
342    def test_scores_csv_upload_available(self):
343        # lecturers can upload a CSV file to set values.
344        self.login_as_lecturer()
345        # set value to change from
346        self.student['studycourse']['100']['COURSE1'].score = 55
347        self.browser.open(self.edit_scores_url)
348        upload_ctrl = self.browser.getControl(name='uploadfile:file')
349        upload_file = StringIO(UPLOAD_CSV_TEMPLATE % ('65','22'))
350        upload_ctrl.add_file(upload_file, 'text/csv', 'myscores.csv')
351        self.browser.getControl("Update editable scores from").click()
352        # value changed
353        self.assertEqual(
354            self.student['studycourse']['100']['COURSE1'].score, 65)
355        self.assertEqual(
356            self.student['studycourse']['100']['COURSE1'].ca, 22)
357
358    def test_lecturers_can_download_course_tickets(self):
359        # A course ticket slip can be downloaded
360        self.login_as_lecturer()
361        pdf_url = '%s/coursetickets.pdf' % self.course_url
362        self.browser.open(pdf_url)
363        self.assertEqual(self.browser.headers['Status'], '200 Ok')
364        self.assertEqual(
365            self.browser.headers['Content-Type'], 'application/pdf')
366        path = os.path.join(samples_dir(), 'coursetickets.pdf')
367        open(path, 'wb').write(self.browser.contents)
368        print "Sample PDF coursetickets.pdf written to %s" % path
369
370class StudentUITests(StudentsFullSetup):
371    """Tests for customized student class views and pages
372    """
373
374    layer = FunctionalLayer
375
376    def setUp(self):
377        super(StudentUITests, self).setUp()
378
379        bedticket = BedTicket()
380        bedticket.booking_session = 2004
381        bedticket.bed_type = u'any bed type'
382        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
383        bedticket.bed_coordinates = u'My bed coordinates'
384        self.student['accommodation'].addBedTicket(bedticket)
385
386    def test_student_payments(self):
387        self.certificate.study_mode = 'ug_ft'
388        self.student['studycourse'].entry_session = 2013
389        self.student['studycourse'].certificate.school_fee_1 = 50250.0
390        self.app['configuration']['2004'].union_fee = 1250.0
391        self.app['configuration']['2004'].welfare_fee = 750.0
392        self.student.nationality = u'NG'
393        # Login
394        IWorkflowState(self.student).setState('cleared')
395        self.browser.open(self.login_path)
396        self.browser.getControl(name="form.login").value = self.student_id
397        self.browser.getControl(name="form.password").value = 'spwd'
398        self.browser.getControl("Login").click()
399        # Test school fee payments
400        self.browser.open(self.student_path + '/payments')
401        self.browser.getLink("Add current session payment ticket").click()
402        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
403        self.browser.getControl("Create ticket").click()
404        self.assertTrue('ticket created' in self.browser.contents)
405        value = self.student['payments'].keys()[0]
406        self.browser.getLink(value).click()
407        self.assertTrue('Amount Authorized' in self.browser.contents)
408        self.assertEqual(self.student['payments'][value].amount_auth, 51750.0)
409        self.browser.open(self.browser.url + '/payment_slip.pdf')
410        self.assertEqual(self.browser.headers['Status'], '200 Ok')
411        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
412        path = os.path.join(samples_dir(), 'payment_slip.pdf')
413        open(path, 'wb').write(self.browser.contents)
414        print "Sample PDF payment_slip.pdf written to %s" % path
415        # Another school fee payment cannot be added
416        self.student['payments'][value].approve()
417        self.browser.open(self.student_path + '/payments')
418        self.browser.getLink("Add current session payment ticket").click()
419        self.browser.getControl(name="form.p_category").value = ['schoolfee']
420        self.browser.getControl("Create ticket").click()
421        self.assertTrue(
422            'You must chose a payment which includes additional fees'
423            in self.browser.contents)
424        #self.assertTrue(
425        #    'Another school fee payment for this session has already been made'
426        #    in self.browser.contents)
427        # Test hostel maintenance payments
428        self.browser.open(self.student_path + '/payments')
429        self.browser.getLink("Add current session payment ticket").click()
430        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
431        self.browser.getControl("Create ticket").click()
432        self.assertTrue('ticket created' in self.browser.contents)
433        value = self.student['payments'].keys()[1]
434        self.browser.getLink(value).click()
435        self.assertTrue('<span>My bed coordinates</span>' in self.browser.contents)
436        self.assertEqual(self.student['payments'][value].amount_auth, 876.0)
437        return
438
439    def test_late_registration(self):
440        # Login
441        delta = timedelta(days=10)
442        self.app['configuration'][
443            '2004'].coursereg_deadline = datetime.now(pytz.utc) - delta
444        IWorkflowState(self.student).setState('school fee paid')
445        # Current session is 2004. Here we test course registration for
446        # returning students.
447        self.student['studycourse'].entry_session = 2003
448        self.browser.open(self.login_path)
449        self.browser.getControl(name="form.login").value = self.student_id
450        self.browser.getControl(name="form.password").value = 'spwd'
451        self.browser.getControl("Login").click()
452        self.browser.open(self.payments_path)
453        self.browser.open(self.payments_path + '/addop')
454        self.browser.getControl(name="form.p_category").value = ['late_registration']
455        self.browser.getControl("Create ticket").click()
456        self.assertMatches('...ticket created...',
457                           self.browser.contents)
458        self.browser.getLink("Study Course").click()
459        self.browser.getLink("Add course list").click()
460        self.assertMatches('...Add current level 100 (Year 1)...',
461                           self.browser.contents)
462        self.browser.getControl("Create course list now").click()
463        self.student['studycourse']['100']['COURSE1'].score = 67
464        self.browser.getLink("100").click()
465        # Course results can't be seen
466        self.assertFalse('<td>67</td>' in self.browser.contents)
467        self.browser.getLink("Edit course list").click()
468        self.assertFalse('<td>67</td>' in self.browser.contents)
469        self.browser.getControl("Register course list").click()
470        self.assertTrue('Course registration has ended. Please pay' in self.browser.contents)
471        self.student['payments'].values()[0].approve()
472        self.browser.getControl("Register course list").click()
473        self.assertTrue('Course list has been registered' in self.browser.contents)
474        self.assertEqual(self.student.state, 'courses registered')
475        # Reset student and check if fresh students are always allowed to
476        # register courses.
477        self.student['studycourse'].entry_session = 2004
478        del self.student['payments'][self.student['payments'].keys()[0]]
479        IWorkflowState(self.student).setState('school fee paid')
480        self.browser.open(self.studycourse_path + '/100/edit')
481        self.browser.getControl("Register course list").click()
482        self.assertTrue('Course list has been registered' in self.browser.contents)
483        return
484
485
486    def deactivated_test_student_course_registration(self):
487        # Add more courses
488        self.course2 = createObject('waeup.Course')
489        self.course2.code = 'COURSE2'
490        self.course2.semester = 2
491        self.course2.credits = 10
492        self.course2.passmark = 40
493        self.app['faculties']['fac1']['dep1'].courses.addCourse(
494            self.course2)
495        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
496            self.course2, level=100)
497        self.course3 = createObject('waeup.Course')
498        self.course3.code = 'COURSE3'
499        self.course3.semester = 3
500        self.course3.credits = 10
501        self.course3.passmark = 40
502        self.app['faculties']['fac1']['dep1'].courses.addCourse(
503            self.course3)
504        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
505            self.course3, level=100)
506
507        # Login as student
508        self.browser.open(self.login_path)
509        IWorkflowState(self.student).setState('school fee paid')
510        self.browser.open(self.login_path)
511        self.browser.getControl(name="form.login").value = self.student_id
512        self.browser.getControl(name="form.password").value = 'spwd'
513        self.browser.getControl("Login").click()
514        # Students can add the current study level
515        self.browser.getLink("Study Course").click()
516        self.browser.getLink("Add course list").click()
517        self.assertMatches('...Add current level 100 (Year 1)...',
518                           self.browser.contents)
519        self.browser.getControl("Create course list now").click()
520        # Student has not paid second instalment, therefore a level
521        # with two course ticket was created (semester 1 and combined)
522        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
523        self.browser.getLink("100").click()
524        self.browser.getLink("Edit course list").click()
525        self.browser.getControl("Add course ticket").click()
526        # Student can't add second semester course
527        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
528        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
529        self.assertFalse('<option value="COURSE2">' in self.browser.contents)
530
531        # Let's remove level and see what happens after 2nd instalment payment
532        del(self.student['studycourse']['100'])
533        payment2 = createObject('waeup.StudentOnlinePayment')
534        payment2.p_category = u'schoolfee_2'
535        payment2.p_session = self.student.current_session
536        self.student['payments']['anykey'] = payment2
537        self.browser.open(self.studycourse_path)
538        self.browser.getLink("Add course list").click()
539        self.browser.getControl("Create course list now").click()
540        # Still only 2 tickets have been created since payment ticket
541        # was not paid
542        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
543        payment2.p_state = u'paid'
544        del(self.student['studycourse']['100'])
545        self.browser.open(self.studycourse_path)
546        self.browser.getLink("Add course list").click()
547        self.browser.getControl("Create course list now").click()
548        # Now 2nd semester course has been added
549        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
550        # Student can add second semester course
551        self.browser.getLink("100").click()
552        self.browser.getLink("Edit course list").click()
553        self.browser.getControl("Add course ticket").click()
554        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
555        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
556        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
557        return
558
559    def test_set_matric_number(self):
560        #payment = createObject('waeup.StudentOnlinePayment')
561        #payment.p_category = u'concessional'
562        #payment.p_id = u'anyid'
563        #payment.p_state = u'paid'
564        #self.student['payments']['anykey'] = payment
565        # Login as student
566        self.browser.open(self.login_path)
567        IWorkflowState(self.student).setState('school fee paid')
568        self.browser.open(self.login_path)
569        self.browser.getControl(name="form.login").value = self.student_id
570        self.browser.getControl(name="form.password").value = 'spwd'
571        self.browser.getControl("Login").click()
572        self.assertRaises(
573            LinkNotFoundError,
574            self.browser.getLink, 'Get Matriculation Number')
575        self.student.matric_number = None
576        site = grok.getSite()
577        site['configuration'].next_matric_integer = 1
578        self.student['studycourse'].certificate.study_mode = 'ug_pt'
579        self.browser.open(self.student_path)
580        self.assertRaises(
581            LinkNotFoundError,
582            self.browser.getLink, 'Download matriculation number slip')
583        self.browser.getLink("Get Matriculation Number").click()
584        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
585            in self.browser.contents)
586        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
587        self.assertRaises(
588            LinkNotFoundError,
589            self.browser.getLink, 'Get Matriculation Number')
590        # Setting matric number is logged.
591        logfile = os.path.join(
592            self.app['datacenter'].storage, 'logs', 'students.log')
593        logcontent = open(logfile).read()
594        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
595                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
596        # Matric Number Slip can be downloaded
597        self.browser.getLink("Download matriculation number slip").click()
598        self.assertEqual(self.browser.headers['Status'], '200 Ok')
599        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
600        path = os.path.join(samples_dir(), 'matric_number_slip.pdf')
601        open(path, 'wb').write(self.browser.contents)
602        print "Sample PDF matric_number_slip.pdf written to %s" % path
603        return
604
605    def test_personal_data_slip(self):
606        # Login as student
607        self.browser.open(self.login_path)
608        IWorkflowState(self.student).setState('school fee paid')
609        self.browser.open(self.login_path)
610        self.browser.getControl(name="form.login").value = self.student_id
611        self.browser.getControl(name="form.password").value = 'spwd'
612        self.browser.getControl("Login").click()
613        self.browser.getLink("Personal Data").click()
614        self.assertRaises(
615            LinkNotFoundError,
616            self.browser.getLink, 'Download personal data slip')
617        self.student.father_name = u'Rudolf'
618        self.browser.open(self.personal_path)
619        self.browser.getLink("Download personal data slip").click()
620        self.assertEqual(self.browser.headers['Status'], '200 Ok')
621        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
622        path = os.path.join(samples_dir(), 'personal_data_slip.pdf')
623        open(path, 'wb').write(self.browser.contents)
624        print "Sample PDF personal_data_slip.pdf written to %s" % path
625        return
626
627    def test_student_course_registration(self):
628        IWorkflowState(self.student).setState('school fee paid')
629        self.browser.open(self.login_path)
630        self.browser.getControl(name="form.login").value = self.student_id
631        self.browser.getControl(name="form.password").value = 'spwd'
632        self.browser.getControl("Login").click()
633        # Now students can add the current study level
634        self.browser.getLink("Study Course").click()
635        self.browser.getLink("Add course list").click()
636        self.assertMatches('...Add current level 100 (Year 1)...',
637                           self.browser.contents)
638        self.browser.getControl("Create course list now").click()
639        # Students can't open the customized pdf course registration slip
640        self.browser.open(
641            self.student_path + '/studycourse/100/course_registration_slip.pdf')
642        self.assertTrue('Forbidden' in self.browser.contents)
643        # They can open slips from the previous session ...
644        self.student['studycourse'].current_level = 200
645        self.browser.open(self.student_path + '/studycourse/100')
646        self.browser.getLink("Download course registration slip").click()
647        self.assertEqual(self.browser.headers['Status'], '200 Ok')
648        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
649        # or if they have registered their course list
650        self.student['studycourse'].current_level = 200
651        IWorkflowState(self.student).setState('courses registered')
652        self.browser.open(self.student_path + '/studycourse/100')
653        self.browser.getLink("Download course registration slip").click()
654        self.assertEqual(self.browser.headers['Status'], '200 Ok')
655        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
656        path = os.path.join(samples_dir(), 'ft_course_registration_slip.pdf')
657        open(path, 'wb').write(self.browser.contents)
658        print "Sample PDF ft_course_registration_slip.pdf written to %s" % path
659
660        self.certificate.study_mode = 'ug_pt'
661        self.browser.open(self.student_path + '/studycourse/100')
662        self.browser.getLink("Download course registration slip").click()
663        self.assertEqual(self.browser.headers['Status'], '200 Ok')
664        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
665        path = os.path.join(samples_dir(), 'pt_course_registration_slip.pdf')
666        open(path, 'wb').write(self.browser.contents)
667        print "Sample PDF pt_course_registration_slip.pdf written to %s" % path
668
669        self.certificate.study_mode = 'special_pg_ft'
670        self.student.matric_number = u'AAU/SPS/FLW/LAW/15/PHD/09504'
671        self.browser.open(self.student_path + '/studycourse/100')
672        self.browser.getLink("Download course registration slip").click()
673        self.assertEqual(self.browser.headers['Status'], '200 Ok')
674        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
675        path = os.path.join(samples_dir(), 'pg_course_registration_slip.pdf')
676        open(path, 'wb').write(self.browser.contents)
677        print "Sample PDF pg_course_registration_slip.pdf written to %s" % path
678
679    def test_student_clearance(self):
680        # Student cant login if their password is not set
681        IWorkflowInfo(self.student).fireTransition('admit')
682        self.browser.open(self.login_path)
683        self.browser.getControl(name="form.login").value = self.student_id
684        self.browser.getControl(name="form.password").value = 'spwd'
685        self.browser.getControl("Login").click()
686        self.assertMatches(
687            '...You logged in...', self.browser.contents)
688        # Admitted student can upload a passport picture
689        self.browser.open(self.student_path + '/change_portrait')
690        ctrl = self.browser.getControl(name='passportuploadedit')
691        file_obj = open(SAMPLE_IMAGE, 'rb')
692        file_ctrl = ctrl.mech_control
693        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
694        self.browser.getControl(
695            name='upload_passportuploadedit').click()
696        self.assertTrue(
697            'src="http://localhost/app/students/E1000000/passport.jpg"'
698            in self.browser.contents)
699        # Student is redirected to the personal data form because
700        # personal data form is not properly filled.
701        self.browser.open(self.student_path + '/start_clearance')
702        self.assertMatches('...Personal data form is not properly filled...',
703                           self.browser.contents)
704        self.assertEqual(self.browser.url, self.student_path + '/edit_personal')
705        self.student.father_name = u'Rudolf'
706        self.browser.open(self.student_path + '/start_clearance')
707        self.assertMatches(
708            '...<h1 class="kofa-content-label">Start clearance</h1>...',
709            self.browser.contents)
710
711    def test_student_accommodation(self):
712        del self.student['accommodation']['2004']
713        self.student['studycourse'].certificate.study_mode = 'dp_ft'
714        # All beds can be assigned
715        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
716        bed1.bed_type = u'regular_male_all'
717        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
718        bed2.bed_type = u'regular_female_all'
719        notify(grok.ObjectModifiedEvent(bed1))
720        notify(grok.ObjectModifiedEvent(bed2))
721        # Login
722        self.browser.open(self.login_path)
723        self.browser.getControl(name="form.login").value = self.student_id
724        self.browser.getControl(name="form.password").value = 'spwd'
725        self.browser.getControl("Login").click()
726        # Students can book accommodation without AC ...
727        self.browser.open(self.acco_path)
728        IWorkflowInfo(self.student).fireTransition('admit')
729        self.browser.getControl("Book accommodation").click()
730        self.assertTrue(
731            'You are not eligible to book accommodation.'
732            in self.browser.contents)
733        self.student['studycourse'].certificate.study_mode = 'ug_ft'
734        self.browser.getControl("Book accommodation").click()
735        self.assertFalse('Activation Code:' in self.browser.contents)
736        self.browser.getControl("Create bed ticket").click()
737        # Bed is randomly selected but, since there is only
738        # one bed for this student, we know that
739        self.assertEqual(self.student['accommodation']['2004'].bed_coordinates,
740            'Hall 1, Block A, Room 101, Bed A (regular_male_all)')
741        # Only the hall name is displayed
742        self.assertEqual(self.student[
743            'accommodation']['2004'].display_coordinates,
744            'Hall 1')
745        self.assertFalse('Hall 1, Block A, Room 101, Bed A'
746            in self.browser.contents)
747        self.assertTrue('<td>Hall 1</td>'
748            in self.browser.contents)
749        return
750
751    def test_handle_courses_by_lecturer(self):
752        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
753        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
754        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
755        # Add course ticket
756        studylevel = createObject(u'waeup.StudentStudyLevel')
757        studylevel.level = 100
758        studylevel.level_session = 2004
759        self.student['studycourse'].addStudentStudyLevel(
760            self.certificate, studylevel)
761        # Assign local Lecturer role for a certificate.
762        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
763        prmlocal = IPrincipalRoleManager(course)
764        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
765        notify(LocalRoleSetEvent(
766            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
767        # Login as lecturer.
768        self.browser.open(self.login_path)
769        self.browser.getControl(name="form.login").value = 'mrslecturer'
770        self.browser.getControl(name="form.password").value = 'mrslecturersecret'
771        self.browser.getControl("Login").click()
772        self.browser.getLink("My Courses").click()
773        self.browser.getLink("COURSE1").click()
774        # Course results can be batch edited via the edit_courses view.
775        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
776        self.app['configuration'].current_academic_session = 2004
777        IWorkflowState(self.student).setState('courses validated')
778        self.browser.open(
779            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
780        self.assertTrue(
781            'input type="text" name="scores:list"'
782            in self.browser.contents)
783        self.browser.getControl(name="scores:list", index=0).value = '55'
784        self.browser.getControl(name="cas:list", index=0).value = '22'
785        self.browser.getControl("Update scores from").click()
786        # New score and ca has been set.
787        self.assertEqual(
788            self.student['studycourse']['100']['COURSE1'].score, 55)
789        self.assertEqual(
790            self.student['studycourse']['100']['COURSE1'].ca, 22)
791        # Score editing has been logged.
792        logfile = os.path.join(
793            self.app['datacenter'].storage, 'logs', 'students.log')
794        logcontent = open(logfile).read()
795        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
796                        'E1000000 100/COURSE1 score updated (55)' in logcontent)
797        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
798                        'E1000000 100/COURSE1 ca updated (22)' in logcontent)
799        # Non-integer scores won't be accepted.
800        self.browser.open(
801            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
802        self.assertTrue('value="55" />' in self.browser.contents)
803        self.browser.getControl(name="scores:list", index=0).value = 'abc'
804        self.browser.getControl("Update scores").click()
805        self.assertTrue('Error: Score(s) and CA(s) of TESTER, Anna have not be updated.'
806            in self.browser.contents)
807        # Scores can be removed.
808        self.browser.open(
809            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
810        self.browser.getControl(name="scores:list", index=0).value = ''
811        self.browser.getControl("Update scores").click()
812        self.assertEqual(
813            self.student['studycourse']['100']['COURSE1'].score, None)
814        logcontent = open(logfile).read()
815        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
816                        'E1000000 100/COURSE1 score updated (None)' in logcontent)
Note: See TracBrowser for help on using the repository browser.