source: main/waeup.uniben/trunk/src/waeup/uniben/students/tests/test_browser.py @ 16390

Last change on this file since 16390 was 16386, checked in by Henrik Bettermann, 4 years ago

Implement medical questionnaire fee.

  • Property svn:keywords set to Id
File size: 61.4 KB
Line 
1## $Id: test_browser.py 16386 2021-01-25 15:35:20Z 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
22from datetime import datetime, timedelta, date
23from StringIO import StringIO
24from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo
25from zope.securitypolicy.interfaces import IPrincipalRoleManager
26from zope.security.interfaces import Unauthorized
27from zope.component.hooks import setSite, clearSite
28from zope.component import getUtility, createObject
29from zope.interface import verify
30from zope.event import notify
31from waeup.kofa.authentication import LocalRoleSetEvent
32from waeup.kofa.app import University
33from waeup.kofa.university.faculty import Faculty
34from waeup.kofa.university.department import Department
35from waeup.kofa.students.tests.test_browser import StudentsFullSetup
36from waeup.kofa.students.accommodation import BedTicket
37from waeup.kofa.hostels.hostel import Hostel, Bed, NOT_OCCUPIED
38from waeup.kofa.testing import FunctionalTestCase
39from waeup.kofa.browser.tests.test_pdf import samples_dir
40from waeup.kofa.interfaces import (
41    IExtFileStore, IFileStoreNameChooser)
42from waeup.kofa.students.interfaces import IStudentsUtils
43from waeup.kofa.tests.test_authentication import SECRET
44from waeup.uniben.testing import FunctionalLayer
45
46SAMPLE_FPM = os.path.join(os.path.dirname(__file__), 'sample.fpm')
47SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
48
49class OfficerUITests(StudentsFullSetup):
50    # Tests for Student class views and pages
51
52    layer = FunctionalLayer
53
54    def test_jhl_idcard_officer(self):
55        # Create library officer
56        self.app['users'].addUser('mrlibrary', SECRET)
57        self.app['users']['mrlibrary'].email = 'library@foo.ng'
58        self.app['users']['mrlibrary'].title = 'Carlo Pitter'
59        prmglobal = IPrincipalRoleManager(self.app)
60        prmglobal.assignRoleToPrincipal(
61            'waeup.LibraryClearanceOfficer', 'mrlibrary')
62        prmglobal.assignRoleToPrincipal(
63            'waeup.StudentsOfficer', 'mrlibrary')
64        self.browser.open(self.login_path)
65        self.browser.getControl(name="form.login").value = 'mrlibrary'
66        self.browser.getControl(name="form.password").value = SECRET
67        self.browser.getControl("Login").click()
68        self.assertMatches('...You logged in...', self.browser.contents)
69        self.browser.open(self.student_path)
70        self.assertFalse('JHL' in self.browser.contents)
71        self.browser.getLink("Switch library access").click()
72        self.assertTrue('Library access enabled' in self.browser.contents)
73        self.assertTrue('JHL' in self.browser.contents)
74        self.browser.getLink("Download JHL Id Card").click()
75        self.assertEqual(self.browser.headers['Status'], '200 Ok')
76        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
77        path = os.path.join(samples_dir(), 'jhl_idcard_officer.pdf')
78        open(path, 'wb').write(self.browser.contents)
79        print "Sample PDF jhl_idcard_officer.pdf written to %s" % path
80
81class StudentUITests(StudentsFullSetup):
82    """Tests for customized student class views and pages
83    """
84
85    layer = FunctionalLayer
86
87    def setUp(self):
88        super(StudentUITests, self).setUp()
89
90    def test_next_session_allowed(self):
91        # Let's see if next_session_allowed works as expected
92        # A, ug_ft, 100
93        IWorkflowState(self.student).setState('returning')
94        self.assertTrue(self.student['studycourse'].next_session_allowed)
95        # Uniben special PG programmes have the same workflow
96        # as UG students
97        self.certificate.study_mode = 'special_pg_pt'
98        self.assertTrue(self.student['studycourse'].next_session_allowed)
99        IWorkflowState(self.student).setState('school fee paid')
100        self.assertFalse(self.student['studycourse'].next_session_allowed)
101        # Now we convert the certificate into a 'regular
102        # postgraduate certificate ...
103        self.certificate.study_mode = 'pg_ft'
104        # ... and voila next session registration is allowed
105        self.assertTrue(self.student['studycourse'].next_session_allowed)
106
107    def test_manage_access(self):
108        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
109        # The student created in the base package is a ug student
110        self.browser.open(self.manage_clearance_path)
111        self.assertMatches('...First Sitting Record...',
112                           self.browser.contents)
113        # There is no pg field in the clearance form
114        self.assertFalse('Second Higher Education Record'
115            in self.browser.contents)
116        # Now we change the study mode ...
117        self.certificate.study_mode = 'pg_ft'
118        self.browser.open(self.clearance_path)
119        # ... and additional pg clearance fields appears
120        self.assertMatches('...Second Higher Education Record...',
121                           self.browser.contents)
122        # But also fields from the ug form are displayed
123        self.assertMatches('...First Sitting Record...',
124                           self.browser.contents)
125        # The same holds for Uniben's special pg students
126        self.certificate.study_mode = 'special_pg_pt'
127        self.browser.open(self.clearance_path)
128        self.assertMatches('...Second Higher Education Record...',
129                           self.browser.contents)
130        self.assertMatches('...First Sitting Record...',
131                           self.browser.contents)
132        # We want to see the signature fields.
133        IWorkflowState(self.student).setState('returning')
134        self.browser.open(self.student_path + '/clearance_slip.pdf')
135        self.assertEqual(self.browser.headers['Status'], '200 Ok')
136        self.assertEqual(self.browser.headers['Content-Type'],
137                         'application/pdf')
138        path = os.path.join(samples_dir(), 'clearance_slip.pdf')
139        open(path, 'wb').write(self.browser.contents)
140        print "Sample PDF clearance_slip.pdf written to %s" % path
141
142    def test_student_access(self):
143        # Students can edit clearance data
144        IWorkflowState(self.student).setState('clearance started')
145        self.student.nationality = u'NG'
146        file_store = getUtility(IExtFileStore)
147        self.browser.open(self.login_path)
148        self.browser.getControl(name="form.login").value = self.student_id
149        self.browser.getControl(name="form.password").value = 'spwd'
150        self.browser.getControl("Login").click()
151        self.browser.open(self.edit_clearance_path)
152        # UG students can't edit date_of_birth, nationality and lga
153        self.assertFalse('form.date_of_birth' in self.browser.contents)
154        self.assertFalse('form.nationality' in self.browser.contents)
155        self.assertFalse('form.lga' in self.browser.contents)
156        # Clearance can only be requested if all required documents
157        # have been uploaded.
158        self.browser.getControl("Save and request clearance").click()
159        self.assertTrue('No birth certificate uploaded'
160            in self.browser.contents)
161        birth_certificate = 'My birth certificate'
162        file_id = IFileStoreNameChooser(self.student).chooseName(
163            attr="birth_certificate.jpg")
164        file_store.createFile(file_id, StringIO(birth_certificate))
165        self.browser.open(self.edit_clearance_path)
166        self.browser.getControl("Save and request clearance").click()
167
168        self.assertTrue('No guarantor/referee letter uploaded'
169            in self.browser.contents)
170        ref_let = 'My ref let'
171        file_id = IFileStoreNameChooser(self.student).chooseName(
172            attr="ref_let.jpg")
173        file_store.createFile(file_id, StringIO(ref_let))
174        self.browser.open(self.edit_clearance_path)
175        self.browser.getControl("Save and request clearance").click()
176
177        self.assertTrue('No acceptance letter uploaded'
178            in self.browser.contents)
179        acc_let = 'My acc let'
180        file_id = IFileStoreNameChooser(self.student).chooseName(
181            attr="acc_let.jpg")
182        file_store.createFile(file_id, StringIO(acc_let))
183        self.browser.open(self.edit_clearance_path)
184        self.browser.getControl("Save and request clearance").click()
185
186        self.assertTrue('No first sitting result uploaded'
187            in self.browser.contents)
188        fst_sit_scan = 'My first sitting result'
189        file_id = IFileStoreNameChooser(self.student).chooseName(
190            attr="fst_sit_scan.jpg")
191        file_store.createFile(file_id, StringIO(fst_sit_scan))
192        self.browser.open(self.edit_clearance_path)
193        self.browser.getControl("Save and request clearance").click()
194
195        #self.assertTrue('No second sitting result uploaded'
196        #    in self.browser.contents)
197        #scd_sit_scan = 'My second sitting result'
198        #file_id = IFileStoreNameChooser(self.student).chooseName(
199        #    attr="scd_sit_scan.jpg")
200        #file_store.createFile(file_id, StringIO(scd_sit_scan))
201        #self.browser.open(self.edit_clearance_path)
202        #self.browser.getControl("Save and request clearance").click()
203
204        self.assertTrue('No affidavit of non-membership of secret cults uploaded'
205            in self.browser.contents)
206        secr_cults = 'My non-membership scan'
207        file_id = IFileStoreNameChooser(self.student).chooseName(
208            attr="secr_cults.jpg")
209        file_store.createFile(file_id, StringIO(secr_cults))
210        # Clearance invitation letter is not yet available
211        self.browser.open(self.clearance_path)
212        self.assertFalse('invitation slip' in self.browser.contents)
213        self.browser.open(self.student_path + '/clearance_invitation_slip.pdf')
214        self.assertTrue('Forbidden' in self.browser.contents)
215        self.browser.open(self.edit_clearance_path)
216        self.browser.getControl("Save and request clearance").click()
217        self.assertTrue('Clearance has been requested'
218            in self.browser.contents)
219        # Now student can export physical_clearance.slip
220        self.app['configuration'].name = u'University of Benin'
221        self.student.physical_clearance_date = u'January 5th, 2015'
222        self.browser.getLink("Clearance Data").click()
223        self.browser.getLink("Download clearance invitation slip").click()
224        self.assertEqual(self.browser.headers['Status'], '200 Ok')
225        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
226        path = os.path.join(samples_dir(), 'clearance_invitation_slip.pdf')
227        open(path, 'wb').write(self.browser.contents)
228        print "Sample PDF clearance_invitation_slip.pdf written to %s" % path
229        # Students can open the personal edit page and see the parent_email field.
230        self.browser.open(self.student_path + '/edit_personal')
231        self.assertTrue('parent_email' in self.browser.contents)
232
233    def test_examination_schedule_slip(self):
234        self.student.flash_notice = u'My Examination Date'
235        self.browser.open(self.login_path)
236        self.browser.getControl(name="form.login").value = self.student_id
237        self.browser.getControl(name="form.password").value = 'spwd'
238        self.browser.getControl("Login").click()
239        self.browser.open(self.student_path)
240        self.browser.getLink("Download examination schedule slip").click()
241        self.assertEqual(self.browser.headers['Status'], '200 Ok')
242        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
243        path = os.path.join(samples_dir(), 'examination_schedule_slip.pdf')
244        open(path, 'wb').write(self.browser.contents)
245        print "Sample PDF examination_schedule_slip.pdf written to %s" % path
246        # If flash_notive does not contain exam' the button does not show up.
247        self.student.flash_notice = u'anything'
248        self.browser.open(self.student_path)
249        self.assertFalse('examination schedule slip' in self.browser.contents)
250
251    def test_jhl_idcard(self):
252        IWorkflowState(self.student).setState('returning')
253        self.browser.open(self.login_path)
254        self.browser.getControl(name="form.login").value = self.student_id
255        self.browser.getControl(name="form.password").value = 'spwd'
256        self.browser.getControl("Login").click()
257        self.assertFalse('JHL' in self.browser.contents)
258        self.student.library = True
259        self.browser.open(self.student_path)
260        self.assertTrue('JHL' in self.browser.contents)
261        self.browser.getLink("Download JHL Id Card").click()
262        self.assertEqual(self.browser.headers['Status'], '200 Ok')
263        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
264        path = os.path.join(samples_dir(), 'jhl_idcard_student.pdf')
265        open(path, 'wb').write(self.browser.contents)
266        print "Sample PDF jhl_idcard_student.pdf written to %s" % path
267        self.assertTrue(self.student.library)
268        IWorkflowInfo(self.student).fireTransition('pay_school_fee')
269        self.assertFalse(self.student.library)
270
271    def test_jupeb_result_slip(self):
272        self.student.flash_notice = u'My JUPEB results'
273        self.browser.open(self.login_path)
274        self.browser.getControl(name="form.login").value = self.student_id
275        self.browser.getControl(name="form.password").value = 'spwd'
276        self.browser.getControl("Login").click()
277        self.assertFalse('JUPEB result slip' in self.browser.contents)
278        # Create JUPEB faculty
279        cert = createObject('waeup.Certificate')
280        cert.code = u'xyz'
281        cert.study_mode = 'found'
282        self.app['faculties']['JUPEB123'] = Faculty(code=u'JUPEB123')
283        self.app['faculties']['JUPEB123']['dep1'] = Department(code=u'dep1')
284        self.app['faculties']['JUPEB123']['dep1'].certificates.addCertificate(cert)
285        self.student['studycourse'].certificate = cert
286        self.browser.open(self.student_path)
287        self.browser.getLink("Download JUPEB result slip").click()
288        self.assertEqual(self.browser.headers['Status'], '200 Ok')
289        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
290        path = os.path.join(samples_dir(), 'jupeb_result_slip.pdf')
291        open(path, 'wb').write(self.browser.contents)
292        print "Sample PDF jupeb_result_slip.pdf written to %s" % path
293        self.student.flash_notice = u''
294        self.browser.open(self.student_path)
295        self.assertFalse('JUPEB result slip' in self.browser.contents)
296
297    def test_manage_payments(self):
298        # Add missing configuration data
299        self.app['configuration']['2004'].gown_fee = 150.0
300        self.app['configuration']['2004'].transfer_fee = 90.0
301        #self.app['configuration']['2004'].clearance_fee = 120.0
302        self.app['configuration']['2004'].booking_fee = 150.0
303        self.app['configuration']['2004'].maint_fee = 180.0
304
305        # Managers can add online payment tickets
306        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
307        self.browser.open(self.payments_path)
308        self.browser.getLink("Add current session payment ticket").click()
309        self.browser.getControl(name="form.p_category").value = ['schoolfee']
310        self.browser.getControl("Create ticket").click()
311        self.assertMatches('...Amount could not be determined...',
312                           self.browser.contents)
313        IWorkflowState(self.student).setState('cleared')
314        self.student.nationality = u'NG'
315        self.browser.open(self.payments_path + '/addop')
316        self.browser.getControl(name="form.p_category").value = ['schoolfee']
317        self.browser.getControl("Create ticket").click()
318        self.assertMatches('...ticket created...',
319                           self.browser.contents)
320        self.assertMatches('...Amount Authorized...',
321                           self.browser.contents)
322        # Managers can open payment slip because we did not proceed to
323        # any payment gateway
324        self.assertFalse('Download payment slip' in self.browser.contents)
325        # Set ticket paid
326        ticket = self.student['payments'].items()[0][1]
327        ticket.p_state = 'paid'
328        self.browser.open(self.payments_path + '/addop')
329        self.browser.getControl(name="form.p_category").value = ['schoolfee']
330        self.browser.getControl("Create ticket").click()
331        self.assertMatches('...This type of payment has already been made...',
332                           self.browser.contents)
333        # Remove all payments so that we can add a school fee payment again
334        keys = [i for i in self.student['payments'].keys()]
335        for payment in keys:
336            del self.student['payments'][payment]
337        self.browser.open(self.payments_path + '/addop')
338        self.browser.getControl(name="form.p_category").value = ['schoolfee']
339        self.browser.getControl("Create ticket").click()
340        self.assertMatches('...ticket created...',
341                           self.browser.contents)
342        schoolfee_ticket = self.student['payments'].values()[0]
343        self.browser.open(self.payments_path + '/addop')
344        self.browser.getControl(name="form.p_category").value = ['gown']
345        self.browser.getControl("Create ticket").click()
346        self.assertMatches('...ticket created...',
347                           self.browser.contents)
348        self.browser.open(self.payments_path + '/addop')
349        self.browser.getControl(name="form.p_category").value = ['clearance']
350        self.browser.getControl("Create ticket").click()
351        self.assertMatches('...ticket created...',
352                           self.browser.contents)
353        self.assertTrue('<span>60000.0</span>' in self.browser.contents)
354        self.browser.open(self.payments_path + '/addop')
355        self.browser.getControl(name="form.p_category").value = ['schoolfee']
356        self.browser.getControl("Create ticket").click()
357        self.assertMatches('...ticket created...',
358                           self.browser.contents)
359        # In state returning we can add a new school fee ticket since
360        # p_session and p_level is different
361        IWorkflowState(self.student).setState('returning')
362        self.browser.open(self.payments_path + '/addop')
363        self.browser.getControl(name="form.p_category").value = ['schoolfee']
364        self.browser.getControl("Create ticket").click()
365        # Uups, we forgot to add a session configuration for next session
366        self.assertMatches('...Session configuration object is not...',
367                           self.browser.contents)
368        configuration = createObject('waeup.SessionConfiguration')
369        configuration.academic_session = 2005
370        self.app['configuration'].addSessionConfiguration(configuration)
371        self.browser.open(self.payments_path + '/addop')
372        self.browser.getControl(name="form.p_category").value = ['schoolfee']
373        self.browser.getControl("Create ticket").click()
374
375        #self.assertMatches('...You have not yet paid your current/active session...',
376        #                   self.browser.contents)
377        ## Ok, let's pay the first schoolfee ticket.
378        #schoolfee_ticket.approve()
379        #self.browser.open(self.payments_path + '/addop')
380        #self.browser.getControl(name="form.p_category").value = ['schoolfee']
381        #self.browser.getControl("Create ticket").click()
382
383        self.assertMatches('...ticket created...',
384                           self.browser.contents)
385        # In state admitted school fee can't be determined
386        IWorkflowState(self.student).setState('admitted')
387        self.browser.open(self.payments_path + '/addop')
388        self.browser.getControl(name="form.p_category").value = ['schoolfee']
389        self.browser.getControl("Create ticket").click()
390        self.assertMatches('...Amount could not be determined...',
391                           self.browser.contents)
392
393        # If the session configuration doesn't exist an error message will
394        # be shown. No other requirement is being checked.
395        del self.app['configuration']['2004']
396        self.browser.open(self.payments_path)
397        self.browser.getLink("Add current session payment ticket").click()
398        self.browser.getControl("Create ticket").click()
399        self.assertMatches('...Session configuration object is not...',
400                           self.browser.contents)
401
402    def test_student_course_registration(self):
403        # Uniben students see grade instead of score on all level pages
404        # and on course ticket page.
405        IWorkflowState(self.student).setState('school fee paid')
406        self.browser.open(self.login_path)
407        self.browser.getControl(name="form.login").value = self.student_id
408        self.browser.getControl(name="form.password").value = 'spwd'
409        self.browser.getControl("Login").click()
410        # Now students can add the current study level
411        self.browser.getLink("Study Course").click()
412        self.browser.getLink("Add course list").click()
413        self.assertMatches('...Add current level 100 (Year 1)...',
414                           self.browser.contents)
415        self.browser.getControl("Create course list now").click()
416        # A level with one course ticket was created
417        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 1)
418        self.student['studycourse']['100']['COURSE1'].score = 55
419        self.browser.getLink("100").click()
420        # GPA has been properly calculated
421        self.assertEqual(self.student['studycourse']['100'].gpa_params[0], 3.0)
422        # Score is not shown but grade
423        self.assertTrue('<th>Grade</th>' in self.browser.contents)
424        self.assertFalse('<th>Score</th>' in self.browser.contents)
425        self.browser.getLink("Edit course list").click()
426        self.assertTrue('<th>Grade</th>' in self.browser.contents)
427        self.assertFalse('<th>Score</th>' in self.browser.contents)
428        self.browser.getLink("COURSE1").click()
429        self.assertFalse('Score' in self.browser.contents)
430        # Students can open the special Uniben pdf course result slip
431        self.browser.open(self.student_path + '/studycourse/100')
432        self.browser.getLink("Download course result slip").click()
433        self.assertEqual(self.browser.headers['Status'], '200 Ok')
434        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
435        # Even if course is mandatory, students can remove the course
436        self.student['studycourse']['100']['COURSE1'].mandatory = True
437        self.browser.open(self.student_path + '/studycourse/100')
438        self.browser.getLink("Edit course list").click()
439        ctrl = self.browser.getControl(name='val_id')
440        ctrl.getControl(value='COURSE1').selected = True
441        self.browser.getControl("Remove selected", index=0).click()
442        self.assertTrue('Successfully removed' in self.browser.contents)
443        # Students can open the customized pdf course registration slip
444        # if they have registered their course list
445        self.browser.open(
446            self.student_path + '/studycourse/100/course_registration_slip.pdf')
447        self.assertTrue('Forbidden' in self.browser.contents)
448        IWorkflowState(self.student).setState('courses registered')
449        self.browser.open(self.student_path + '/studycourse/100')
450        self.browser.getLink("Download course registration slip").click()
451        self.assertEqual(self.browser.headers['Status'], '200 Ok')
452        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
453        path = os.path.join(samples_dir(), 'course_registration_slip.pdf')
454        open(path, 'wb').write(self.browser.contents)
455        print "Sample PDF course_registration_slip.pdf written to %s" % path
456       # Students can always download pdf course result slip
457        self.browser.open(
458            self.student_path + '/studycourse/100/course_result_slip.pdf')
459        self.assertEqual(self.browser.headers['Status'], '200 Ok')
460        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
461        path = os.path.join(samples_dir(), 'course_result_slip.pdf')
462        open(path, 'wb').write(self.browser.contents)
463        print "Sample PDF course_result_slip.pdf written to %s" % path
464
465    def test_get_returning_data(self):
466        # Student is in level 100, session 2004 with verdict A
467        utils = getUtility(IStudentsUtils)
468        self.assertEqual(utils.getReturningData(self.student),(2005, 200))
469        self.student['studycourse'].current_verdict = 'C'
470        self.assertEqual(utils.getReturningData(self.student),(2005, 110))
471        self.student['studycourse'].current_verdict = 'D'
472        self.assertEqual(utils.getReturningData(self.student),(2005, 100))
473        return
474
475    def test_set_returning_data(self):
476        # Student is in level 100, session 2004 with verdict A
477        utils = getUtility(IStudentsUtils)
478
479        utils.setReturningData(self.student)
480        self.assertEqual(self.student['studycourse'].current_session, 2005)
481        self.assertEqual(self.student['studycourse'].current_level, 200)
482
483        self.student['studycourse'].current_session = 2004
484        self.student['studycourse'].current_level = 100
485        self.student['studycourse'].current_verdict = 'C'
486        utils.setReturningData(self.student)
487        self.assertEqual(self.student['studycourse'].current_session, 2005)
488        self.assertEqual(self.student['studycourse'].current_level, 110)
489
490        self.student['studycourse'].current_session = 2004
491        self.student['studycourse'].current_level = 100
492        self.student['studycourse'].current_verdict = 'D'
493        utils.setReturningData(self.student)
494        self.assertEqual(self.student['studycourse'].current_session, 2005)
495        self.assertEqual(self.student['studycourse'].current_level, 100)
496        return
497
498    def test_set_payment_details(self):
499        self.app['configuration']['2004'].gown_fee = 150.0
500        self.app['configuration']['2004'].transfer_fee = 90.0
501        self.app['configuration']['2004'].booking_fee = 150.0
502        self.app['configuration']['2004'].maint_fee = 180.0
503
504        configuration = createObject('waeup.SessionConfiguration')
505        configuration.academic_session = 2000
506        self.app['configuration'].addSessionConfiguration(configuration)
507        configuration2 = createObject('waeup.SessionConfiguration')
508        configuration2.academic_session = 2002
509        self.app['configuration'].addSessionConfiguration(configuration2)
510        configuration3 = createObject('waeup.SessionConfiguration')
511        configuration3.academic_session = 2003
512        self.app['configuration'].addSessionConfiguration(configuration3)
513        configuration4 = createObject('waeup.SessionConfiguration')
514        configuration4.academic_session = 2005
515        self.app['configuration'].addSessionConfiguration(configuration4)
516        utils = getUtility(IStudentsUtils)
517        self.student['studycourse'].entry_session = 2002
518        self.student.nationality = u'NG'
519
520        error, payment = utils.setPaymentDetails('schoolfee',
521            self.student, None, None, None)
522        self.assertEqual(payment, None)
523        # Student is in state 'created' and can thus not pay.
524        self.assertTrue(u'Amount could not be determined.' in error)
525
526        # Previous session must be valid.
527        error, payment = utils.setPaymentDetails('schoolfee',
528            self.student, 2000, 300, None)
529        self.assertEqual(payment, None)
530        self.assertTrue(u'The previous session must not fall below' in error)
531        error, payment = utils.setPaymentDetails('schoolfee',
532            self.student, 2005, 300, None)
533        self.assertEqual(payment, None)
534        self.assertTrue(u'This is not a previous session' in error)
535
536        # Previous session schoolfee payment; fresh and returning
537        # are distinguished by their entry_level
538        error, payment = utils.setPaymentDetails('schoolfee',
539            self.student, 2002, 300, None)
540        self.assertEqual(payment.amount_auth, 40000.0)
541        self.assertEqual(payment.p_session, 2002)
542        self.assertEqual(payment.p_level, 300)
543        self.assertFalse(payment.p_current)
544        error, payment = utils.setPaymentDetails('schoolfee',
545            self.student, 2003, 300, None)
546        self.assertEqual(payment.amount_auth, 20000.0)
547        self.assertEqual(payment.p_session, 2003)
548        self.assertEqual(payment.p_level, 300)
549        self.assertFalse(payment.p_current)
550
551        # Current schoolfee payment; fresh and returning
552        # are distinguished by their state
553        IWorkflowState(self.student).setState('cleared')
554        error, payment = utils.setPaymentDetails('schoolfee',
555            self.student, None, None, None)
556        self.assertEqual(payment.p_level, 100)
557        self.assertEqual(payment.p_session, 2004)
558        self.assertEqual(payment.amount_auth, 40000.0)
559        self.assertEqual(payment.p_item, u'CERT1')
560        self.assertEqual(error, None)
561        self.assertTrue(payment.p_current)
562
563        # Add penalty fee ...
564        # ... for cleared
565        self.app['configuration']['2004'].penalty_ug_ft = 99.0
566        # ... for returning
567        self.app['configuration']['2005'].penalty_ug_ft = 88.0
568        error, payment = utils.setPaymentDetails('schoolfee',
569            self.student, None, None, None)
570        self.assertEqual(payment.amount_auth, 40099.0)
571
572        IWorkflowState(self.student).setState('returning')
573
574        #error, payment = utils.setPaymentDetails('schoolfee',
575        #    self.student, None, None, None)
576        #self.assertTrue(
577        #    u'You have not yet paid your current/active session.' in error)
578        ## Ok, that means we have to add paid payment ticket first.
579        #payment = createObject('waeup.StudentOnlinePayment')
580        #payment.p_category = u'schoolfee'
581        #payment.p_session = self.student.current_session
582        #payment.p_item = u'My Certificate'
583        #payment.p_id = u'anyid'
584        #payment.p_state = u'paid'
585        #self.student['payments']['anykey'] = payment
586
587        error, payment = utils.setPaymentDetails('schoolfee',
588            self.student, None, None, None)
589        self.assertEqual(payment.p_level, 200)
590        self.assertEqual(payment.p_session, 2005)
591        self.assertEqual(payment.amount_auth, 20088.0)
592        self.assertEqual(payment.p_item, u'CERT1')
593        self.assertEqual(error, None)
594
595        # Old returning students may pay less.
596        self.certificate.school_fee_2 = 50000.0
597        self.certificate.custom_float_1 = 30000.0
598        error, payment = utils.setPaymentDetails(
599            'schoolfee', self.student, None, None, None)
600        self.assertEqual(payment.amount_auth, 20088.0)
601
602        # Staff members pay less.
603        self.certificate.custom_float_1 = None
604        self.student.is_staff = True
605        error, payment = utils.setPaymentDetails('schoolfee',
606            self.student, None, None, None)
607        self.assertEqual(payment.p_level, 200)
608        self.assertEqual(payment.p_session, 2005)
609        self.assertEqual(payment.amount_auth, 25088.0)
610        self.assertEqual(payment.p_item, u'CERT1')
611        self.assertEqual(error, None)
612
613        # Foreigners pay more.
614        IWorkflowState(self.student).setState('cleared')
615        self.student.is_staff = False
616        self.student.nationality = u'DE'
617        self.certificate.school_fee_3 = 60000.0
618        error, payment = utils.setPaymentDetails(
619            'schoolfee', self.student, None, None, None)
620        self.assertEqual(payment.p_level, 100)
621        self.assertEqual(payment.p_session, 2004)
622        self.assertEqual(payment.amount_auth, 60099.0)
623        self.assertEqual(payment.p_item, u'CERT1')
624        self.assertEqual(error, None)
625        IWorkflowState(self.student).setState('returning')
626        self.student.is_staff = False
627        self.certificate.school_fee_4 = 20000.0
628        error, payment = utils.setPaymentDetails(
629            'schoolfee', self.student, None, None, None)
630        self.assertEqual(payment.p_level, 200)
631        self.assertEqual(payment.p_session, 2005)
632        self.assertEqual(payment.amount_auth, 20088.0)
633        self.assertEqual(payment.p_item, u'CERT1')
634        self.assertEqual(error, None)
635
636        # In Uniben students can pay school fee in all states no matter
637        # if they are ug or pg students.
638        # diabled on 02/10/2017, see ticket 1108
639        #IWorkflowState(self.student).setState('school fee paid')
640        #self.student.is_staff = False
641        #self.student.nationality = u'NG'
642        #self.certificate.school_fee_2 = 10000.0
643        #error, payment = utils.setPaymentDetails(
644        #    'schoolfee', self.student, None, None, None)
645        #self.assertEqual(payment.p_level, None)
646        #self.assertEqual(payment.p_session, 2005)
647        #self.assertEqual(payment.amount_auth, 10088.0)
648        #self.assertEqual(payment.p_item, u'CERT1')
649        #self.assertEqual(error, None)
650        #IWorkflowState(self.student).setState('courses registered')
651        #self.certificate.study_mode = 'special_pg_pt'
652        #error, payment = utils.setPaymentDetails(
653        #    'schoolfee', self.student, None, None, None)
654        #self.assertEqual(payment.p_level, None)
655        #self.assertEqual(payment.p_session, 2005)
656        #self.assertEqual(payment.amount_auth, 10000.0)
657        #self.assertEqual(payment.p_item, u'CERT1')
658        #self.assertEqual(error, None)
659        #IWorkflowState(self.student).setState('courses validated')
660        #error, payment = utils.setPaymentDetails(
661        #    'schoolfee', self.student, None, None, None)
662        #self.assertEqual(payment.p_level, None)
663        #self.assertEqual(payment.p_session, 2005)
664        #self.assertEqual(payment.amount_auth, 10000.0)
665        #self.assertEqual(payment.p_item, u'CERT1')
666        #self.assertEqual(error, None)
667
668        error, payment = utils.setPaymentDetails('clearance',
669            self.student, None, None, None)
670        self.assertEqual(payment.p_level, 100)
671        self.assertEqual(payment.p_session, 2004)
672        self.assertEqual(payment.amount_auth, 60000.0)
673        self.assertEqual(payment.p_item, u'CERT1')
674        self.assertEqual(error, None)
675
676        error, payment = utils.setPaymentDetails('gown',
677            self.student, None, None, None)
678        self.assertEqual(payment.p_level, 100)
679        self.assertEqual(payment.p_session, 2004)
680        self.assertEqual(payment.amount_auth, 150.0)
681        self.assertEqual(payment.p_item, u'')
682        self.assertEqual(error, None)
683
684        bedticket = BedTicket()
685        bedticket.booking_session = 2004
686        bedticket.bed_type = u'any bed type'
687        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
688        bedticket.bed_coordinates = u'My bed coordinates'
689        self.student['accommodation'].addBedTicket(bedticket)
690
691        error, payment = utils.setPaymentDetails('hostel_maintenance',
692            self.student, None, None, None)
693        self.assertEqual(payment.p_level, 100)
694        self.assertEqual(payment.p_session, 2004)
695        self.assertEqual(payment.amount_auth, 876.0)
696        self.assertEqual(payment.p_item, u'My bed coordinates')
697        self.assertEqual(error, None)
698
699        #self.certificate.study_mode = 'ug_ft'
700        #error, payment = utils.setPaymentDetails('bed_allocation',
701        #    self.student, None, None, None)
702        #self.assertTrue(u'Amount could not be determined.' in error)
703        #self.student['studycourse'].current_session = 2004
704        #self.student['studycourse'].entry_session = 2004
705        #self.student['studycourse'].current_level = 100
706        #error, payment = utils.setPaymentDetails('bed_allocation',
707        #    self.student, None, None, None)
708        #self.assertEqual(payment.p_level, 100)
709        #self.assertEqual(payment.p_session, 2004)
710        #self.assertEqual(payment.amount_auth, 650.0) # plus 500 student union
711        #self.assertEqual(payment.p_item, u'regular_male_fr')
712        #self.assertEqual(error, None)
713
714        self.certificate.study_mode = 'pg_ft'
715        error, payment = utils.setPaymentDetails('bed_allocation',
716            self.student, None, None, None)
717        self.assertEqual(error, u'Select your favoured hostel first.')
718        self.student['accommodation'].desired_hostel = u'no'
719        error, payment = utils.setPaymentDetails('bed_allocation',
720            self.student, None, None, None)
721        self.assertEqual(payment.p_level, 100)
722        self.assertEqual(payment.p_session, 2004)
723        self.assertEqual(payment.amount_auth, 650.0)
724        self.assertEqual(payment.p_item, u'pg_male_all')
725        self.assertEqual(error, None)
726
727        #error, payment = utils.setPaymentDetails('hostel_application',
728        #    self.student, None, None, None)
729        #self.assertEqual(payment.p_level, 100)
730        #self.assertEqual(payment.p_session, 2004)
731        #self.assertEqual(payment.amount_auth, 1000.0)
732        #self.assertEqual(payment.p_item, u'')
733        #self.assertEqual(error, None)
734
735        #payment.approve()
736        #self.student['payments'][payment.p_id] = payment
737
738        #error, payment = utils.setPaymentDetails('tempmaint_1',
739        #    self.student, None, None, None)
740        #self.assertEqual(payment.p_level, 100)
741        #self.assertEqual(payment.p_session, 2004)
742        #self.assertEqual(payment.amount_auth, 8150.0)
743        #self.assertEqual(payment.p_item, u'Hall 1-4 M/F Ekehuan')
744        #self.assertEqual(error, None)
745
746        #error, payment = utils.setPaymentDetails('tempmaint_2',
747        #    self.student, None, None, None)
748        #self.assertEqual(payment.p_level, 100)
749        #self.assertEqual(payment.p_session, 2004)
750        #self.assertEqual(payment.amount_auth, 12650.0)
751        #self.assertEqual(payment.p_item, u'Hall 5 M/F')
752        #self.assertEqual(error, None)
753
754        #error, payment = utils.setPaymentDetails('tempmaint_3',
755        #    self.student, None, None, None)
756        #self.assertEqual(payment.p_level, 100)
757        #self.assertEqual(payment.p_session, 2004)
758        #self.assertEqual(payment.amount_auth, 9650.0)
759        #self.assertEqual(payment.p_item, u'Clinical Hostel')
760        #self.assertEqual(error, None)
761
762        error, payment = utils.setPaymentDetails('transfer',
763            self.student, None, None, None)
764        self.assertEqual(payment.p_level, 100)
765        self.assertEqual(payment.p_session, 2004)
766        self.assertEqual(payment.amount_auth, 90.0)
767        self.assertEqual(payment.p_item, u'')
768        self.assertEqual(error, None)
769        return
770
771    def test_edit_level_by_co(self):
772        # Create clearance officer
773        self.app['users'].addUser('mrclear', 'mrClearsecret1')
774        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
775        self.app['users']['mrclear'].title = 'Carlo Pitter'
776        # Assign local ClearanceOfficer role
777        department = self.app['faculties']['fac1']['dep1']
778        prmlocal = IPrincipalRoleManager(department)
779        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
780        notify(LocalRoleSetEvent(
781            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
782        IWorkflowState(self.student).setState('clearance started')
783        # Login as clearance officer
784        self.browser.open(self.login_path)
785        self.browser.getControl(name="form.login").value = 'mrclear'
786        self.browser.getControl(name="form.password").value = 'mrClearsecret1'
787        self.browser.getControl("Login").click()
788        self.assertMatches('...You logged in...', self.browser.contents)
789        # Only in state clearance requested the CO does see the
790        # 'Edit level' button ...
791        self.browser.open(self.studycourse_path)
792        self.assertFalse('Edit level' in self.browser.contents)
793        # ... and can open the edit_level view
794        self.browser.open(self.studycourse_path + '/edit_level')
795        self.assertMatches('...is locked...', self.browser.contents)
796        self.assertEqual(self.browser.url, self.studycourse_path)
797        IWorkflowInfo(self.student).fireTransition('request_clearance')
798        self.browser.open(self.studycourse_path)
799        self.assertTrue('Edit level' in self.browser.contents)
800        self.browser.getLink("Edit level").click()
801        self.browser.getControl(name="form.current_level").value = ['200']
802        self.browser.getControl("Save").click()
803        self.assertMatches('...has been saved...', self.browser.contents)
804        self.assertEqual(self.student.current_level, 200)
805
806    def test_postgraduate_student_access(self):
807        self.certificate.study_mode = 'special_pg_pt'
808        self.certificate.start_level = 700
809        self.certificate.end_level = 800
810        self.student['studycourse'].current_level = 700
811        IWorkflowState(self.student).setState('school fee paid')
812        self.browser.open(self.login_path)
813        self.browser.getControl(name="form.login").value = self.student_id
814        self.browser.getControl(name="form.password").value = 'spwd'
815        self.browser.getControl("Login").click()
816        self.assertTrue(
817            'You logged in.' in self.browser.contents)
818        # Now students can add the current study level
819        self.browser.getLink("Study Course").click()
820        self.browser.getLink("Add course list").click()
821        self.assertMatches('...Add current level 700...',
822                           self.browser.contents)
823        self.browser.getControl("Create course list now").click()
824        # A level with no course ticket was created
825        self.assertEqual(self.student['studycourse']['700'].number_of_tickets, 0)
826        self.browser.getLink("700").click()
827        self.browser.getLink("Edit course list").click()
828        self.browser.getLink("here").click()
829        self.browser.getControl(name="form.course").value = ['COURSE1']
830        # Non-final year students can't add ticket with 51 credits
831        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
832        self.browser.getControl("Add course ticket").click()
833        self.assertMatches('...Maximum credits exceeded...',
834                           self.browser.contents)
835        # Final year students can't add ticket with 52 credits ...
836        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 52
837        self.student['studycourse'].certificate.end_level = 700
838        self.browser.getControl("Add course ticket").click()
839        self.assertMatches('...Maximum credits exceeded...',
840                           self.browser.contents)
841        # ... but with 51 credits
842        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
843        self.browser.getControl("Add course ticket").click()
844        self.assertMatches('...Successfully added COURSE1...',
845                           self.browser.contents)
846        # Non-final year special postgraduate students can't register
847        # course lists if their total credits are 51 and thus exceed 50 ...
848        self.student['studycourse'].certificate.end_level = 800
849        self.browser.getControl("Register course list").click()
850        self.assertMatches('...Maximum credits exceeded...',
851            self.browser.contents)
852        # ... but final year students can
853        self.student['studycourse'].certificate.end_level = 700
854        self.browser.getControl("Register course list").click()
855        self.assertMatches('...Course list has been registered...',
856            self.browser.contents)
857        self.assertEqual(self.student.state, 'courses registered')
858        return
859
860    def test_login(self):
861        # If suspended_comment is set this message will be flashed instead
862        self.student.suspended_comment = u'Aetsch baetsch!'
863        self.student.suspended = True
864        self.browser.open(self.login_path)
865        self.browser.getControl(name="form.login").value = self.student_id
866        self.browser.getControl(name="form.password").value = 'spwd'
867        self.browser.getControl("Login").click()
868        # Uniben does not display suspended_comment
869        self.assertMatches(
870            '...<div class="alert alert-warning">Your account has been deactivated.</div>...',
871            self.browser.contents)
872        self.student.suspended = False
873
874    def test_activate_deactivate_buttons(self):
875        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
876        self.browser.open(self.student_path)
877        self.browser.getLink("Deactivate").click()
878        self.assertTrue(
879            'Student account has been deactivated.' in self.browser.contents)
880        self.assertTrue(
881            'Base Data (account deactivated)' in self.browser.contents)
882        self.assertTrue(self.student.suspended)
883        self.browser.getLink("Activate").click()
884        self.assertTrue(
885            'Student account has been activated.' in self.browser.contents)
886        self.assertFalse(
887            'Base Data (account deactivated)' in self.browser.contents)
888        self.assertFalse(self.student.suspended)
889        # History messages have been added ...
890        self.browser.getLink("History").click()
891        # User is undisclosed
892        self.assertTrue(
893            'Student account deactivated<br />' in self.browser.contents)
894        self.assertTrue(
895            'Student account activated<br />' in self.browser.contents)
896        # ... and actions have been logged.
897        logfile = os.path.join(
898            self.app['datacenter'].storage, 'logs', 'students.log')
899        logcontent = open(logfile).read()
900        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentDeactivateView - '
901                        'B1000000 - account deactivated' in logcontent)
902        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentActivateView - '
903                        'B1000000 - account activated' in logcontent)
904
905    def test_manage_upload_fpm_file(self):
906        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
907        self.browser.open(self.manage_clearance_path)
908        image = open(SAMPLE_FPM, 'rb')
909        ctrl = self.browser.getControl(name='leftthumbprintupload')
910        file_ctrl = ctrl.mech_control
911        file_ctrl.add_file(image, filename='thumbprint.fpm')
912        self.browser.getControl(
913            name='upload_leftthumbprintupload').click()
914        self.assertTrue(
915            'File finger1.fpm uploaded.' in self.browser.contents)
916        self.assertTrue(
917            'http://localhost/app/students/B1000000/finger1.fpm'
918            in self.browser.contents)
919        self.browser.getControl(
920            name='delete_leftthumbprintupload').click()
921        self.assertTrue(
922            'finger1.fpm deleted'
923            in self.browser.contents)
924
925    def test_handle_clearance_by_co(self):
926        # Create clearance officer
927        self.app['users'].addUser('mrclear', 'mrClearsecret1')
928        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
929        self.app['users']['mrclear'].title = 'Carlo Pitter'
930        department = self.app['faculties']['fac1']['dep1']
931        prmlocal = IPrincipalRoleManager(department)
932        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
933        notify(LocalRoleSetEvent(
934            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
935        IWorkflowState(self.student).setState('clearance requested')
936        # Login as clearance officer
937        self.browser.open(self.login_path)
938        self.browser.getControl(name="form.login").value = 'mrclear'
939        self.browser.getControl(name="form.password").value = 'mrClearsecret1'
940        self.browser.getControl("Login").click()
941        self.assertMatches('...You logged in...', self.browser.contents)
942        # CO can view the student ...
943        self.browser.open(self.clearance_path)
944        self.assertEqual(self.browser.headers['Status'], '200 Ok')
945        self.assertEqual(self.browser.url, self.clearance_path)
946        # Clearance is disabled for this session for ug students ...
947        self.browser.open(self.clearance_path)
948        self.assertFalse('Clear student' in self.browser.contents)
949        self.browser.open(self.student_path + '/clear')
950        self.assertTrue('Clearance is disabled for this session'
951            in self.browser.contents)
952        # ... but not for
953        self.certificate.study_mode = 'pg_ft'
954        self.browser.open(self.clearance_path)
955        self.assertTrue('Clear student' in self.browser.contents)
956        self.browser.open(self.student_path + '/clear')
957        self.assertTrue('Student has been cleared' in self.browser.contents)
958
959    def test_transcripts(self):
960        studylevel = createObject(u'waeup.StudentStudyLevel')
961        IWorkflowState(self.student).setState('transcript validated')
962        studylevel.level = 100
963        studylevel.level_session = 2005
964        self.student['studycourse'].entry_mode = 'ug_ft'
965        self.student['studycourse'].addStudentStudyLevel(
966            self.certificate, studylevel)
967        studylevel2 = createObject(u'waeup.StudentStudyLevel')
968        studylevel2.level = 110
969        studylevel2.level_session = 2006
970        self.student['studycourse'].addStudentStudyLevel(
971            self.certificate, studylevel2)
972        # Add second course (COURSE has been added automatically)
973        courseticket = createObject('waeup.CourseTicket')
974        courseticket.code = 'ANYCODE'
975        courseticket.title = u'Any TITLE'
976        courseticket.credits = 13
977        courseticket.score = 66
978        courseticket.semester = 1
979        courseticket.dcode = u'ANYDCODE'
980        courseticket.fcode = u'ANYFCODE'
981        self.student['studycourse']['110']['COURSE2'] = courseticket
982        self.student['studycourse']['100']['COURSE1'].score = 55
983        self.assertEqual(self.student['studycourse']['100'].gpa_params_rectified[0], 3.0)
984        self.assertEqual(self.student['studycourse']['110'].gpa_params_rectified[0], 4.0)
985        # Get transcript data
986        td = self.student['studycourse'].getTranscriptData()
987        self.assertEqual(td[0][0]['level_key'], '100')
988        self.assertEqual(td[0][0]['sgpa'], 3.0)
989        self.assertEqual(td[0][0]['level'].level, 100)
990        self.assertEqual(td[0][0]['level'].level_session, 2005)
991        self.assertEqual(td[0][0]['tickets_1'][0].code, 'COURSE1')
992        self.assertEqual(td[0][1]['level_key'], '110')
993        self.assertEqual(td[0][1]['sgpa'], 4.0)
994        self.assertEqual(td[0][1]['level'].level, 110)
995        self.assertEqual(td[0][1]['level'].level_session, 2006)
996        self.assertEqual(td[0][1]['tickets_1'][0].code, 'ANYCODE')
997        self.assertEqual(td[1], 3.5652173913043477)
998        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
999        self.browser.open(self.student_path + '/studycourse/transcript')
1000        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1001        self.assertTrue('Transcript' in self.browser.contents)
1002        # Officers can open the pdf transcript
1003        self.browser.open(self.student_path + '/studycourse/transcript.pdf')
1004        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1005        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1006        path = os.path.join(samples_dir(), 'transcript.pdf')
1007        open(path, 'wb').write(self.browser.contents)
1008        print "Sample PDF transcript.pdf written to %s" % path
1009
1010    def test_student_accommodation(self):
1011        self.app['hostels'].allocation_expiration = 7
1012        self.student['accommodation'].desired_hostel = u'hall-1'
1013        bed = Bed()
1014        bed.bed_id = u'hall-1_A_101_C'
1015        bed.bed_number = 3
1016        bed.owner = NOT_OCCUPIED
1017        bed.bed_type = u'regular_male_fi'
1018        self.app['hostels']['hall-1'].addBed(bed)
1019        self.browser.open(self.login_path)
1020        self.browser.getControl(name="form.login").value = self.student_id
1021        self.browser.getControl(name="form.password").value = 'spwd'
1022        self.browser.getControl("Login").click()
1023        # Students can add online booking fee payment tickets and open the
1024        # callback view (see test_manage_payments).
1025        self.browser.getLink("Payments").click()
1026        self.browser.getLink("Add current session payment ticket").click()
1027        self.browser.getControl(name="form.p_category").value = ['bed_allocation']
1028        self.browser.getControl("Create ticket").click()
1029        p_ticket = self.student['payments'].values()[0]
1030        self.assertEqual(p_ticket.p_item, 'regular_male_fr (hall-1)')
1031        p_ticket.approveStudentPayment()
1032        # The new HOS-0 pin has been created.
1033        self.assertEqual(len(self.app['accesscodes']['HOS-0']),1)
1034        pin = self.app['accesscodes']['HOS-0'].keys()[0]
1035        ac = self.app['accesscodes']['HOS-0'][pin]
1036        parts = pin.split('-')[1:]
1037        sfeseries, sfenumber = parts
1038        # Students can use HOS code and book a bed space with it ...
1039        self.browser.open(self.acco_path)
1040        # ... but not if booking period has expired ...
1041        self.app['hostels'].enddate = datetime.now(pytz.utc)
1042        self.browser.getControl("Book accommodation").click()
1043        self.assertMatches('...Outside booking period: ...',
1044                           self.browser.contents)
1045        self.app['hostels'].enddate = datetime.now(pytz.utc) + timedelta(days=10)
1046        # ... or student data are incomplete ...
1047        self.student['studycourse'].current_level = None
1048        self.browser.getControl("Book accommodation").click()
1049        self.assertMatches('...Your data are incomplete...',
1050            self.browser.contents)
1051        self.student['studycourse'].current_level = 200
1052        # ... or student is not the an allowed state ...
1053        self.browser.getControl("Book accommodation").click()
1054        self.assertMatches('...You are in the wrong...',
1055                           self.browser.contents)
1056        self.app['hostels'].accommodation_states = ['admitted', 'school fee paid']
1057        IWorkflowState(self.student).setState('school fee paid')
1058        # ... or student has not appropriate verdict (Uniben only!)
1059        self.student['studycourse'].entry_session = 2000 # non-fresh
1060        self.student['studycourse'].current_level = 500 # final-year
1061        self.student['studycourse'].current_verdict = 'C'
1062        self.browser.getControl("Book accommodation").click()
1063        self.assertMatches('...Your are not eligible...',
1064            self.browser.contents)
1065        self.student['studycourse'].previous_verdict = 'A'
1066        self.browser.getControl("Book accommodation").click()
1067        self.assertMatches('...Activation Code:...',
1068                           self.browser.contents)
1069        # Student can't use faked ACs ...
1070        self.browser.getControl(name="ac_series").value = u'nonsense'
1071        self.browser.getControl(name="ac_number").value = sfenumber
1072        self.browser.getControl("Create bed ticket").click()
1073        self.assertMatches('...Activation code is invalid...',
1074                           self.browser.contents)
1075        # ... or ACs owned by somebody else.
1076        ac.owner = u'Anybody'
1077        self.browser.getControl(name="ac_series").value = sfeseries
1078        self.browser.getControl(name="ac_number").value = sfenumber
1079        self.browser.getControl("Create bed ticket").click()
1080        self.assertMatches('...You are not the owner of this access code...',
1081                           self.browser.contents)
1082        # The bed remains empty.
1083        bed = self.app['hostels']['hall-1']['hall-1_A_101_C']
1084        self.assertTrue(bed.owner == NOT_OCCUPIED)
1085        ac.owner = self.student_id
1086        self.browser.getControl(name="ac_series").value = sfeseries
1087        self.browser.getControl(name="ac_number").value = sfenumber
1088        self.browser.getControl("Create bed ticket").click()
1089        self.assertMatches('...Hall 1, Block/Unit A, Room 101, Bed C...',
1090                           self.browser.contents)
1091        # Bed has been allocated.
1092        self.assertTrue(bed.owner == self.student_id)
1093        # BedTicketAddPage is now blocked.
1094        self.browser.getControl("Book accommodation").click()
1095        self.assertMatches('...You already booked a bed space...',
1096            self.browser.contents)
1097        # The bed ticket displays the data correctly.
1098        self.browser.open(self.acco_path + '/2004')
1099        self.assertMatches('...Hall 1, Block/Unit A, Room 101, Bed C...',
1100                           self.browser.contents)
1101        self.assertMatches('...2004/2005...', self.browser.contents)
1102        self.assertMatches('...regular_male_fi...', self.browser.contents)
1103        self.assertMatches('...%s...' % pin, self.browser.contents)
1104        # Students can open the pdf slip.
1105        self.browser.open(self.browser.url + '/bed_allocation_slip.pdf')
1106        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1107        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1108        path = os.path.join(samples_dir(), 'bed_allocation_slip.pdf')
1109        open(path, 'wb').write(self.browser.contents)
1110        print "Sample PDF bed_allocation_slip.pdf written to %s" % path
1111        # Students can't relocate themselves.
1112        self.assertFalse('Relocate' in self.browser.contents)
1113        relocate_path = self.acco_path + '/2004/relocate'
1114        self.assertRaises(
1115            Unauthorized, self.browser.open, relocate_path)
1116        # Students can't see the Remove button and check boxes.
1117        self.browser.open(self.acco_path)
1118        self.assertFalse('Remove' in self.browser.contents)
1119        self.assertFalse('val_id' in self.browser.contents)
1120        # Students can pay maintenance fee now.
1121        self.browser.open(self.payments_path)
1122        self.browser.open(self.payments_path + '/addop')
1123        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
1124        self.browser.getControl("Create ticket").click()
1125        self.assertMatches('...Payment ticket created...',
1126                           self.browser.contents)
1127        # Maintennace fee is taken from the hostel object.
1128        self.assertEqual(self.student['payments'].values()[1].amount_auth, 876.0)
1129        # If the hostel's maintenance fee isn't set, the fee is
1130        # taken from the session configuration object.
1131        self.app['hostels']['hall-1'].maint_fee = 0.0
1132        self.browser.open(self.payments_path + '/addop')
1133        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
1134        self.browser.getControl("Create ticket").click()
1135        self.assertEqual(self.student['payments'].values()[2].amount_auth, 987.0)
1136        return
1137
1138    def test_student_clearance(self):
1139        # create some passport file for `student`
1140        storage = getUtility(IExtFileStore)
1141        image_path = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
1142        self.image_contents = open(image_path, 'rb').read()
1143        file_id = IFileStoreNameChooser(self.student).chooseName(
1144            attr='passport.jpg')
1145        storage.createFile(file_id, StringIO(self.image_contents))
1146        IWorkflowInfo(self.student).fireTransition('admit')
1147        self.browser.open(self.login_path)
1148        self.browser.getControl(name="form.login").value = self.student_id
1149        self.browser.getControl(name="form.password").value = 'spwd'
1150        self.browser.getControl("Login").click()
1151        self.assertMatches(
1152            '...You logged in...', self.browser.contents)
1153        self.browser.getLink("Base Data").click()
1154        self.browser.getLink("Download admission letter").click()
1155        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1156        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1157        path = os.path.join(samples_dir(), 'admission_slip.pdf')
1158        open(path, 'wb').write(self.browser.contents)
1159        print "Sample PDF admission_slip.pdf written to %s" % path
1160        self.browser.open(self.student_path + '/start_clearance')
1161        # Regular students have to enter an access code
1162        self.browser.getControl("Start clearance now").click()
1163        self.assertTrue('Activation code is invalid' in self.browser.contents)
1164        # DCOEM students can start clearance without access code
1165        self.app['faculties']['fac1'].code = 'DCOEM'
1166        self.browser.open(self.student_path + '/start_clearance')
1167        self.browser.getControl("Start clearance now").click()
1168        self.assertMatches('...Clearance process has been started...',
1169                           self.browser.contents)
1170
1171    def test_student_medical_questionnaire(self):
1172        self.app['configuration']['2004'].medical_quest_fee = 1000.0
1173        IWorkflowInfo(self.student).fireTransition('admit')
1174        self.browser.open(self.login_path)
1175        self.browser.getControl(name="form.login").value = self.student_id
1176        self.browser.getControl(name="form.password").value = 'spwd'
1177        self.browser.getControl("Login").click()
1178        self.assertMatches(
1179            '...You logged in...', self.browser.contents)
1180        self.browser.getLink("Base Data").click()
1181        self.browser.getLink("Medical Questionnaire").click()
1182        self.assertTrue('Please pay medical questionnaire payment first' in
1183            self.browser.contents)
1184        self.assertEqual(self.browser.url, self.student_path)
1185        self.browser.open(self.payments_path)
1186        self.browser.getLink("Add current session payment ticket").click()
1187        self.browser.getControl(name="form.p_category").value = ['medical_quest']
1188        self.browser.getControl("Create ticket").click()
1189        p_ticket = self.student['payments'].values()[0]
1190        p_ticket.approveStudentPayment()
1191        self.browser.getLink("Base Data").click()
1192        self.browser.getLink("Medical Questionnaire").click()
1193        self.browser.getLink("Download medical questionnaire slip").click()
1194        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1195        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1196        path = os.path.join(samples_dir(), 'medical_questionnaire_slip.pdf')
1197        open(path, 'wb').write(self.browser.contents)
1198        print "Sample PDF medical_questionnaire_slip.pdf written to %s" % path
Note: See TracBrowser for help on using the repository browser.