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

Last change on this file since 13723 was 13723, checked in by Henrik Bettermann, 9 years ago

Add exam schedule examination slip.

Fix test.

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