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

Last change on this file since 16340 was 16330, checked in by Henrik Bettermann, 4 years ago

Adjust tests.

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