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

Last change on this file since 15574 was 15574, checked in by Henrik Bettermann, 5 years ago

DCOEM students don't pay acceptance fee.

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