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

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

Implement first draft of bursary clearance slip.

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