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

Last change on this file since 15164 was 15106, checked in by Henrik Bettermann, 6 years ago

Add payment category.

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