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

Last change on this file since 15062 was 15002, checked in by Henrik Bettermann, 7 years ago

PG students pay higher booking fee.

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