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

Last change on this file since 17932 was 17885, checked in by Henrik Bettermann, 3 months ago

Provide affidavit of good conduct form.

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