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

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

Do only allow adding bed_allocation payments if desired_hostel is set.

  • Property svn:keywords set to Id
File size: 56.0 KB
Line 
1## $Id: test_browser.py 15314 2019-01-29 21:47:26Z 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(error, u'Select your favoured hostel first.')
687        self.student['accommodation'].desired_hostel = u'no'
688        error, payment = utils.setPaymentDetails('bed_allocation',
689            self.student, None, None)
690        self.assertEqual(payment.p_level, 100)
691        self.assertEqual(payment.p_session, 2004)
692        self.assertEqual(payment.amount_auth, 650.0)
693        self.assertEqual(payment.p_item, u'pg_male_all')
694        self.assertEqual(error, None)
695
696        #error, payment = utils.setPaymentDetails('hostel_application',
697        #    self.student, None, None)
698        #self.assertEqual(payment.p_level, 100)
699        #self.assertEqual(payment.p_session, 2004)
700        #self.assertEqual(payment.amount_auth, 1000.0)
701        #self.assertEqual(payment.p_item, u'')
702        #self.assertEqual(error, None)
703
704        #payment.approve()
705        #self.student['payments'][payment.p_id] = payment
706
707        #error, payment = utils.setPaymentDetails('tempmaint_1',
708        #    self.student, None, None)
709        #self.assertEqual(payment.p_level, 100)
710        #self.assertEqual(payment.p_session, 2004)
711        #self.assertEqual(payment.amount_auth, 8150.0)
712        #self.assertEqual(payment.p_item, u'Hall 1-4 M/F Ekehuan')
713        #self.assertEqual(error, None)
714
715        #error, payment = utils.setPaymentDetails('tempmaint_2',
716        #    self.student, None, None)
717        #self.assertEqual(payment.p_level, 100)
718        #self.assertEqual(payment.p_session, 2004)
719        #self.assertEqual(payment.amount_auth, 12650.0)
720        #self.assertEqual(payment.p_item, u'Hall 5 M/F')
721        #self.assertEqual(error, None)
722
723        #error, payment = utils.setPaymentDetails('tempmaint_3',
724        #    self.student, None, None)
725        #self.assertEqual(payment.p_level, 100)
726        #self.assertEqual(payment.p_session, 2004)
727        #self.assertEqual(payment.amount_auth, 9650.0)
728        #self.assertEqual(payment.p_item, u'Clinical Hostel')
729        #self.assertEqual(error, None)
730
731        error, payment = utils.setPaymentDetails('transfer',
732            self.student, None, None)
733        self.assertEqual(payment.p_level, 100)
734        self.assertEqual(payment.p_session, 2004)
735        self.assertEqual(payment.amount_auth, 90.0)
736        self.assertEqual(payment.p_item, u'')
737        self.assertEqual(error, None)
738        return
739
740    def test_edit_level_by_co(self):
741        # Create clearance officer
742        self.app['users'].addUser('mrclear', 'mrClearsecret1')
743        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
744        self.app['users']['mrclear'].title = 'Carlo Pitter'
745        # Assign local ClearanceOfficer role
746        department = self.app['faculties']['fac1']['dep1']
747        prmlocal = IPrincipalRoleManager(department)
748        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
749        notify(LocalRoleSetEvent(
750            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
751        IWorkflowState(self.student).setState('clearance started')
752        # Login as clearance officer
753        self.browser.open(self.login_path)
754        self.browser.getControl(name="form.login").value = 'mrclear'
755        self.browser.getControl(name="form.password").value = 'mrClearsecret1'
756        self.browser.getControl("Login").click()
757        self.assertMatches('...You logged in...', self.browser.contents)
758        # Only in state clearance requested the CO does see the
759        # 'Edit level' button ...
760        self.browser.open(self.studycourse_path)
761        self.assertFalse('Edit level' in self.browser.contents)
762        # ... and can open the edit_level view
763        self.browser.open(self.studycourse_path + '/edit_level')
764        self.assertMatches('...is locked...', self.browser.contents)
765        self.assertEqual(self.browser.url, self.studycourse_path)
766        IWorkflowInfo(self.student).fireTransition('request_clearance')
767        self.browser.open(self.studycourse_path)
768        self.assertTrue('Edit level' in self.browser.contents)
769        self.browser.getLink("Edit level").click()
770        self.browser.getControl(name="form.current_level").value = ['200']
771        self.browser.getControl("Save").click()
772        self.assertMatches('...has been saved...', self.browser.contents)
773        self.assertEqual(self.student.current_level, 200)
774
775    def test_postgraduate_student_access(self):
776        self.certificate.study_mode = 'special_pg_pt'
777        self.certificate.start_level = 700
778        self.certificate.end_level = 800
779        self.student['studycourse'].current_level = 700
780        IWorkflowState(self.student).setState('school fee paid')
781        self.browser.open(self.login_path)
782        self.browser.getControl(name="form.login").value = self.student_id
783        self.browser.getControl(name="form.password").value = 'spwd'
784        self.browser.getControl("Login").click()
785        self.assertTrue(
786            'You logged in.' in self.browser.contents)
787        # Now students can add the current study level
788        self.browser.getLink("Study Course").click()
789        self.browser.getLink("Add course list").click()
790        self.assertMatches('...Add current level 700...',
791                           self.browser.contents)
792        self.browser.getControl("Create course list now").click()
793        # A level with no course ticket was created
794        self.assertEqual(self.student['studycourse']['700'].number_of_tickets, 0)
795        self.browser.getLink("700").click()
796        self.browser.getLink("Edit course list").click()
797        self.browser.getLink("here").click()
798        self.browser.getControl(name="form.course").value = ['COURSE1']
799        # Non-final year students can't add ticket with 51 credits
800        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
801        self.browser.getControl("Add course ticket").click()
802        self.assertMatches('...Maximum credits exceeded...',
803                           self.browser.contents)
804        # Final year students can't add ticket with 52 credits ...
805        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 52
806        self.student['studycourse'].certificate.end_level = 700
807        self.browser.getControl("Add course ticket").click()
808        self.assertMatches('...Maximum credits exceeded...',
809                           self.browser.contents)
810        # ... but with 51 credits
811        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
812        self.browser.getControl("Add course ticket").click()
813        self.assertMatches('...Successfully added COURSE1...',
814                           self.browser.contents)
815        # Non-final year special postgraduate students can't register
816        # course lists if their total credits are 51 and thus exceed 50 ...
817        self.student['studycourse'].certificate.end_level = 800
818        self.browser.getControl("Register course list").click()
819        self.assertMatches('...Maximum credits exceeded...',
820            self.browser.contents)
821        # ... but final year students can
822        self.student['studycourse'].certificate.end_level = 700
823        self.browser.getControl("Register course list").click()
824        self.assertMatches('...Course list has been registered...',
825            self.browser.contents)
826        self.assertEqual(self.student.state, 'courses registered')
827        return
828
829    def test_login(self):
830        # If suspended_comment is set this message will be flashed instead
831        self.student.suspended_comment = u'Aetsch baetsch!'
832        self.student.suspended = True
833        self.browser.open(self.login_path)
834        self.browser.getControl(name="form.login").value = self.student_id
835        self.browser.getControl(name="form.password").value = 'spwd'
836        self.browser.getControl("Login").click()
837        # Uniben does not display suspended_comment
838        self.assertMatches(
839            '...<div class="alert alert-warning">Your account has been deactivated.</div>...',
840            self.browser.contents)
841        self.student.suspended = False
842
843    def test_activate_deactivate_buttons(self):
844        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
845        self.browser.open(self.student_path)
846        self.browser.getLink("Deactivate").click()
847        self.assertTrue(
848            'Student account has been deactivated.' in self.browser.contents)
849        self.assertTrue(
850            'Base Data (account deactivated)' in self.browser.contents)
851        self.assertTrue(self.student.suspended)
852        self.browser.getLink("Activate").click()
853        self.assertTrue(
854            'Student account has been activated.' in self.browser.contents)
855        self.assertFalse(
856            'Base Data (account deactivated)' in self.browser.contents)
857        self.assertFalse(self.student.suspended)
858        # History messages have been added ...
859        self.browser.getLink("History").click()
860        # User is undisclosed
861        self.assertTrue(
862            'Student account deactivated<br />' in self.browser.contents)
863        self.assertTrue(
864            'Student account activated<br />' in self.browser.contents)
865        # ... and actions have been logged.
866        logfile = os.path.join(
867            self.app['datacenter'].storage, 'logs', 'students.log')
868        logcontent = open(logfile).read()
869        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentDeactivateView - '
870                        'B1000000 - account deactivated' in logcontent)
871        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentActivateView - '
872                        'B1000000 - account activated' in logcontent)
873
874    def test_manage_upload_fpm_file(self):
875        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
876        self.browser.open(self.manage_clearance_path)
877        image = open(SAMPLE_FPM, 'rb')
878        ctrl = self.browser.getControl(name='leftthumbprintupload')
879        file_ctrl = ctrl.mech_control
880        file_ctrl.add_file(image, filename='thumbprint.fpm')
881        self.browser.getControl(
882            name='upload_leftthumbprintupload').click()
883        self.assertTrue(
884            'File finger1.fpm uploaded.' in self.browser.contents)
885        self.assertTrue(
886            'http://localhost/app/students/B1000000/finger1.fpm'
887            in self.browser.contents)
888        self.browser.getControl(
889            name='delete_leftthumbprintupload').click()
890        self.assertTrue(
891            'finger1.fpm deleted'
892            in self.browser.contents)
893
894    def test_handle_clearance_by_co(self):
895        # Create clearance officer
896        self.app['users'].addUser('mrclear', 'mrClearsecret1')
897        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
898        self.app['users']['mrclear'].title = 'Carlo Pitter'
899        department = self.app['faculties']['fac1']['dep1']
900        prmlocal = IPrincipalRoleManager(department)
901        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
902        notify(LocalRoleSetEvent(
903            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
904        IWorkflowState(self.student).setState('clearance requested')
905        # Login as clearance officer
906        self.browser.open(self.login_path)
907        self.browser.getControl(name="form.login").value = 'mrclear'
908        self.browser.getControl(name="form.password").value = 'mrClearsecret1'
909        self.browser.getControl("Login").click()
910        self.assertMatches('...You logged in...', self.browser.contents)
911        # CO can view the student ...
912        self.browser.open(self.clearance_path)
913        self.assertEqual(self.browser.headers['Status'], '200 Ok')
914        self.assertEqual(self.browser.url, self.clearance_path)
915        # Clearance is disabled for this session for ug students ...
916        self.browser.open(self.clearance_path)
917        self.assertFalse('Clear student' in self.browser.contents)
918        self.browser.open(self.student_path + '/clear')
919        self.assertTrue('Clearance is disabled for this session'
920            in self.browser.contents)
921        # ... but not for
922        self.certificate.study_mode = 'pg_ft'
923        self.browser.open(self.clearance_path)
924        self.assertTrue('Clear student' in self.browser.contents)
925        self.browser.open(self.student_path + '/clear')
926        self.assertTrue('Student has been cleared' in self.browser.contents)
927
928    def test_transcripts(self):
929        studylevel = createObject(u'waeup.StudentStudyLevel')
930        studylevel.level = 100
931        studylevel.level_session = 2005
932        self.student['studycourse'].entry_mode = 'ug_ft'
933        self.student['studycourse'].addStudentStudyLevel(
934            self.certificate, studylevel)
935        studylevel2 = createObject(u'waeup.StudentStudyLevel')
936        studylevel2.level = 110
937        studylevel2.level_session = 2006
938        self.student['studycourse'].addStudentStudyLevel(
939            self.certificate, studylevel2)
940        # Add second course (COURSE has been added automatically)
941        courseticket = createObject('waeup.CourseTicket')
942        courseticket.code = 'ANYCODE'
943        courseticket.title = u'Any TITLE'
944        courseticket.credits = 13
945        courseticket.score = 66
946        courseticket.semester = 1
947        courseticket.dcode = u'ANYDCODE'
948        courseticket.fcode = u'ANYFCODE'
949        self.student['studycourse']['110']['COURSE2'] = courseticket
950        self.student['studycourse']['100']['COURSE1'].score = 55
951        self.assertEqual(self.student['studycourse']['100'].gpa_params_rectified[0], 3.0)
952        self.assertEqual(self.student['studycourse']['110'].gpa_params_rectified[0], 4.0)
953        # Get transcript data
954        td = self.student['studycourse'].getTranscriptData()
955        self.assertEqual(td[0][0]['level_key'], '100')
956        self.assertEqual(td[0][0]['sgpa'], 3.0)
957        self.assertEqual(td[0][0]['level'].level, 100)
958        self.assertEqual(td[0][0]['level'].level_session, 2005)
959        self.assertEqual(td[0][0]['tickets_1'][0].code, 'COURSE1')
960        self.assertEqual(td[0][1]['level_key'], '110')
961        self.assertEqual(td[0][1]['sgpa'], 4.0)
962        self.assertEqual(td[0][1]['level'].level, 110)
963        self.assertEqual(td[0][1]['level'].level_session, 2006)
964        self.assertEqual(td[0][1]['tickets_1'][0].code, 'ANYCODE')
965        self.assertEqual(td[1], 3.5652173913043477)
966        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
967        self.browser.open(self.student_path + '/studycourse/transcript')
968        self.assertEqual(self.browser.headers['Status'], '200 Ok')
969        self.assertTrue('Transcript' in self.browser.contents)
970        # Officers can open the pdf transcript
971        self.browser.open(self.student_path + '/studycourse/transcript.pdf')
972        self.assertEqual(self.browser.headers['Status'], '200 Ok')
973        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
974        path = os.path.join(samples_dir(), 'transcript.pdf')
975        open(path, 'wb').write(self.browser.contents)
976        print "Sample PDF transcript.pdf written to %s" % path
977
978    def test_student_accommodation(self):
979        self.app['hostels'].allocation_expiration = 7
980        self.student['accommodation'].desired_hostel = u'hall-1'
981        bed = Bed()
982        bed.bed_id = u'hall-1_A_101_C'
983        bed.bed_number = 3
984        bed.owner = NOT_OCCUPIED
985        bed.bed_type = u'regular_male_fi'
986        self.app['hostels']['hall-1'].addBed(bed)
987        self.browser.open(self.login_path)
988        self.browser.getControl(name="form.login").value = self.student_id
989        self.browser.getControl(name="form.password").value = 'spwd'
990        self.browser.getControl("Login").click()
991        # Students can add online booking fee payment tickets and open the
992        # callback view (see test_manage_payments).
993        self.browser.getLink("Payments").click()
994        self.browser.getLink("Add current session payment ticket").click()
995        self.browser.getControl(name="form.p_category").value = ['bed_allocation']
996        self.browser.getControl("Create ticket").click()
997        p_ticket = self.student['payments'].values()[0]
998        self.assertEqual(p_ticket.p_item, 'regular_male_fr (hall-1)')
999        p_ticket.approveStudentPayment()
1000        # The new HOS-0 pin has been created.
1001        self.assertEqual(len(self.app['accesscodes']['HOS-0']),1)
1002        pin = self.app['accesscodes']['HOS-0'].keys()[0]
1003        ac = self.app['accesscodes']['HOS-0'][pin]
1004        parts = pin.split('-')[1:]
1005        sfeseries, sfenumber = parts
1006        # Students can use HOS code and book a bed space with it ...
1007        self.browser.open(self.acco_path)
1008        # ... but not if booking period has expired ...
1009        self.app['hostels'].enddate = datetime.now(pytz.utc)
1010        self.browser.getControl("Book accommodation").click()
1011        self.assertMatches('...Outside booking period: ...',
1012                           self.browser.contents)
1013        self.app['hostels'].enddate = datetime.now(pytz.utc) + timedelta(days=10)
1014        # ... or student data are incomplete ...
1015        self.student['studycourse'].current_level = None
1016        self.browser.getControl("Book accommodation").click()
1017        self.assertMatches('...Your data are incomplete...',
1018            self.browser.contents)
1019        self.student['studycourse'].current_level = 200
1020        # ... or student is not the an allowed state ...
1021        self.browser.getControl("Book accommodation").click()
1022        self.assertMatches('...You are in the wrong...',
1023                           self.browser.contents)
1024        self.app['hostels'].accommodation_states = ['admitted', 'school fee paid']
1025        IWorkflowState(self.student).setState('school fee paid')
1026        # ... or student has not appropriate verdict (Uniben only!)
1027        self.student['studycourse'].entry_session = 2000 # non-fresh
1028        self.student['studycourse'].current_level = 500 # final-year
1029        self.student['studycourse'].current_verdict = 'C'
1030        self.browser.getControl("Book accommodation").click()
1031        self.assertMatches('...Your are not eligible...',
1032            self.browser.contents)
1033        self.student['studycourse'].previous_verdict = 'A'
1034        self.browser.getControl("Book accommodation").click()
1035        self.assertMatches('...Activation Code:...',
1036                           self.browser.contents)
1037        # Student can't use faked ACs ...
1038        self.browser.getControl(name="ac_series").value = u'nonsense'
1039        self.browser.getControl(name="ac_number").value = sfenumber
1040        self.browser.getControl("Create bed ticket").click()
1041        self.assertMatches('...Activation code is invalid...',
1042                           self.browser.contents)
1043        # ... or ACs owned by somebody else.
1044        ac.owner = u'Anybody'
1045        self.browser.getControl(name="ac_series").value = sfeseries
1046        self.browser.getControl(name="ac_number").value = sfenumber
1047        self.browser.getControl("Create bed ticket").click()
1048        self.assertMatches('...You are not the owner of this access code...',
1049                           self.browser.contents)
1050        # The bed remains empty.
1051        bed = self.app['hostels']['hall-1']['hall-1_A_101_C']
1052        self.assertTrue(bed.owner == NOT_OCCUPIED)
1053        ac.owner = self.student_id
1054        self.browser.getControl(name="ac_series").value = sfeseries
1055        self.browser.getControl(name="ac_number").value = sfenumber
1056        self.browser.getControl("Create bed ticket").click()
1057        self.assertMatches('...Hall 1, Block/Unit A, Room 101, Bed C...',
1058                           self.browser.contents)
1059        # Bed has been allocated.
1060        self.assertTrue(bed.owner == self.student_id)
1061        # BedTicketAddPage is now blocked.
1062        self.browser.getControl("Book accommodation").click()
1063        self.assertMatches('...You already booked a bed space...',
1064            self.browser.contents)
1065        # The bed ticket displays the data correctly.
1066        self.browser.open(self.acco_path + '/2004')
1067        self.assertMatches('...Hall 1, Block/Unit A, Room 101, Bed C...',
1068                           self.browser.contents)
1069        self.assertMatches('...2004/2005...', self.browser.contents)
1070        self.assertMatches('...regular_male_fi...', self.browser.contents)
1071        self.assertMatches('...%s...' % pin, self.browser.contents)
1072        # Students can open the pdf slip.
1073        self.browser.open(self.browser.url + '/bed_allocation_slip.pdf')
1074        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1075        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1076        path = os.path.join(samples_dir(), 'bed_allocation_slip.pdf')
1077        open(path, 'wb').write(self.browser.contents)
1078        print "Sample PDF bed_allocation_slip.pdf written to %s" % path
1079        # Students can't relocate themselves.
1080        self.assertFalse('Relocate' in self.browser.contents)
1081        relocate_path = self.acco_path + '/2004/relocate'
1082        self.assertRaises(
1083            Unauthorized, self.browser.open, relocate_path)
1084        # Students can't see the Remove button and check boxes.
1085        self.browser.open(self.acco_path)
1086        self.assertFalse('Remove' in self.browser.contents)
1087        self.assertFalse('val_id' in self.browser.contents)
1088        # Students can pay maintenance fee now.
1089        self.browser.open(self.payments_path)
1090        self.browser.open(self.payments_path + '/addop')
1091        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
1092        self.browser.getControl("Create ticket").click()
1093        self.assertMatches('...Payment ticket created...',
1094                           self.browser.contents)
1095        # Maintennace fee is taken from the hostel object.
1096        self.assertEqual(self.student['payments'].values()[1].amount_auth, 876.0)
1097        # If the hostel's maintenance fee isn't set, the fee is
1098        # taken from the session configuration object.
1099        self.app['hostels']['hall-1'].maint_fee = 0.0
1100        self.browser.open(self.payments_path + '/addop')
1101        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
1102        self.browser.getControl("Create ticket").click()
1103        self.assertEqual(self.student['payments'].values()[2].amount_auth, 987.0)
1104        return
Note: See TracBrowser for help on using the repository browser.