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

Last change on this file since 17503 was 17457, checked in by Henrik Bettermann, 19 months ago

Implement new school fee calculation based on civ configuration tables.

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