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

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

Students must upload new passport picture before requesting clearance.

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