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

Last change on this file since 18100 was 18100, checked in by Henrik Bettermann, 7 days ago

Fix tests.

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