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

Last change on this file since 17626 was 17542, checked in by Henrik Bettermann, 17 months ago

Implement medical examination form.

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