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

Last change on this file since 15393 was 15371, checked in by Henrik Bettermann, 6 years ago

Implement a library access switch.

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