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

Last change on this file since 16447 was 16447, checked in by Henrik Bettermann, 3 years ago

See #1207.

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