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

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

Only ug_ft students must upload picture.

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