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

Last change on this file since 12852 was 12846, checked in by Henrik Bettermann, 10 years ago

Move signatures into footer.

  • Property svn:keywords set to Id
File size: 44.3 KB
Line 
1## $Id: test_browser.py 12846 2015-04-02 16:06:57Z 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
21from StringIO import StringIO
22from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo
23from zope.securitypolicy.interfaces import IPrincipalRoleManager
24from zope.component.hooks import setSite, clearSite
25from zope.component import getUtility, createObject
26from zope.interface import verify
27from zope.event import notify
28from waeup.kofa.authentication import LocalRoleSetEvent
29from waeup.kofa.app import University
30from waeup.kofa.students.tests.test_browser import StudentsFullSetup
31from waeup.kofa.students.accommodation import BedTicket
32from waeup.kofa.testing import FunctionalTestCase
33from waeup.kofa.browser.tests.test_pdf import samples_dir
34from waeup.kofa.interfaces import (
35    IExtFileStore, IFileStoreNameChooser)
36from waeup.kofa.students.interfaces import IStudentsUtils
37from waeup.uniben.testing import FunctionalLayer
38
39SAMPLE_FPM = os.path.join(os.path.dirname(__file__), 'sample.fpm')
40
41class StudentUITests(StudentsFullSetup):
42    """Tests for customized student class views and pages
43    """
44
45    layer = FunctionalLayer
46
47    def setUp(self):
48        super(StudentUITests, self).setUp()
49
50        bedticket = BedTicket()
51        bedticket.booking_session = 2004
52        bedticket.bed_type = u'any bed type'
53        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
54        bedticket.bed_coordinates = u'My bed coordinates'
55        self.student['accommodation'].addBedTicket(bedticket)
56
57    def test_next_session_allowed(self):
58        # Let's see if next_session_allowed works as expected
59        # A, ug_ft, 100
60        IWorkflowState(self.student).setState('returning')
61        self.assertTrue(self.student['studycourse'].next_session_allowed)
62        # Uniben special PG programmes have the same workflow
63        # as UG students
64        self.certificate.study_mode = 'special_pg_pt'
65        self.assertTrue(self.student['studycourse'].next_session_allowed)
66        IWorkflowState(self.student).setState('school fee paid')
67        self.assertFalse(self.student['studycourse'].next_session_allowed)
68        # Now we convert the certificate into a 'regular
69        # postgraduate certificate ...
70        self.certificate.study_mode = 'pg_ft'
71        # ... and voila next session registration is allowed
72        self.assertTrue(self.student['studycourse'].next_session_allowed)
73
74    def test_manage_access(self):
75        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
76        # The student created in the base package is a ug student
77        self.browser.open(self.manage_clearance_path)
78        self.assertMatches('...First Sitting Record...',
79                           self.browser.contents)
80        # There is no pg field in the clearance form
81        self.assertFalse('Second Higher Education Record'
82            in self.browser.contents)
83        # Now we change the study mode ...
84        self.certificate.study_mode = 'pg_ft'
85        self.browser.open(self.clearance_path)
86        # ... and additional pg clearance fields appears
87        self.assertMatches('...Second Higher Education Record...',
88                           self.browser.contents)
89        # But also fields from the ug form are displayed
90        self.assertMatches('...First Sitting Record...',
91                           self.browser.contents)
92        # The same holds for Uniben's special pg students
93        self.certificate.study_mode = 'special_pg_pt'
94        self.browser.open(self.clearance_path)
95        self.assertMatches('...Second Higher Education Record...',
96                           self.browser.contents)
97        self.assertMatches('...First Sitting Record...',
98                           self.browser.contents)
99        # We want to see the signature fields.
100        IWorkflowState(self.student).setState('returning')
101        self.browser.open(self.student_path + '/clearance_slip.pdf')
102        self.assertEqual(self.browser.headers['Status'], '200 Ok')
103        self.assertEqual(self.browser.headers['Content-Type'],
104                         'application/pdf')
105        path = os.path.join(samples_dir(), 'clearance_slip.pdf')
106        open(path, 'wb').write(self.browser.contents)
107        print "Sample PDF clearance_slip.pdf written to %s" % path
108
109    def test_student_access(self):
110        # Students can edit clearance data
111        IWorkflowState(self.student).setState('clearance started')
112        self.student.clearance_locked = False
113        self.student.nationality = u'NG'
114        file_store = getUtility(IExtFileStore)
115        self.browser.open(self.login_path)
116        self.browser.getControl(name="form.login").value = self.student_id
117        self.browser.getControl(name="form.password").value = 'spwd'
118        self.browser.getControl("Login").click()
119        self.browser.open(self.edit_clearance_path)
120        # UG students can't edit date_of_birth, nationality and lga
121        self.assertFalse('form.date_of_birth' in self.browser.contents)
122        self.assertFalse('form.nationality' in self.browser.contents)
123        self.assertFalse('form.lga' in self.browser.contents)
124        # Clearance can only be requested if all required documents
125        # have been uploaded.
126        self.browser.getControl("Save and request clearance").click()
127        self.assertTrue('No birth certificate uploaded'
128            in self.browser.contents)
129        birth_certificate = 'My birth certificate'
130        file_id = IFileStoreNameChooser(self.student).chooseName(
131            attr="birth_certificate.jpg")
132        file_store.createFile(file_id, StringIO(birth_certificate))
133        self.browser.open(self.edit_clearance_path)
134        self.browser.getControl("Save and request clearance").click()
135
136        self.assertTrue('No guarantor/referee letter uploaded'
137            in self.browser.contents)
138        ref_let = 'My ref let'
139        file_id = IFileStoreNameChooser(self.student).chooseName(
140            attr="ref_let.jpg")
141        file_store.createFile(file_id, StringIO(ref_let))
142        self.browser.open(self.edit_clearance_path)
143        self.browser.getControl("Save and request clearance").click()
144
145        self.assertTrue('No acceptance letter uploaded'
146            in self.browser.contents)
147        acc_let = 'My acc let'
148        file_id = IFileStoreNameChooser(self.student).chooseName(
149            attr="acc_let.jpg")
150        file_store.createFile(file_id, StringIO(acc_let))
151        self.browser.open(self.edit_clearance_path)
152        self.browser.getControl("Save and request clearance").click()
153
154        self.assertTrue('No first sitting result uploaded'
155            in self.browser.contents)
156        fst_sit_scan = 'My first sitting result'
157        file_id = IFileStoreNameChooser(self.student).chooseName(
158            attr="fst_sit_scan.jpg")
159        file_store.createFile(file_id, StringIO(fst_sit_scan))
160        self.browser.open(self.edit_clearance_path)
161        self.browser.getControl("Save and request clearance").click()
162
163        #self.assertTrue('No second sitting result uploaded'
164        #    in self.browser.contents)
165        #scd_sit_scan = 'My second sitting result'
166        #file_id = IFileStoreNameChooser(self.student).chooseName(
167        #    attr="scd_sit_scan.jpg")
168        #file_store.createFile(file_id, StringIO(scd_sit_scan))
169        #self.browser.open(self.edit_clearance_path)
170        #self.browser.getControl("Save and request clearance").click()
171
172        self.assertTrue('No affidavit of non-membership of secret cults uploaded'
173            in self.browser.contents)
174        secr_cults = 'My non-membership scan'
175        file_id = IFileStoreNameChooser(self.student).chooseName(
176            attr="secr_cults.jpg")
177        file_store.createFile(file_id, StringIO(secr_cults))
178        # Clearance invitation letter is not yet available
179        self.browser.open(self.clearance_path)
180        self.assertFalse('invitation slip' in self.browser.contents)
181        self.browser.open(self.student_path + '/clearance_invitation_slip.pdf')
182        self.assertTrue('Forbidden' in self.browser.contents)
183        self.browser.open(self.edit_clearance_path)
184        self.browser.getControl("Save and request clearance").click()
185        self.assertTrue('Clearance has been requested'
186            in self.browser.contents)
187        # Now student can export physical_clearance.slip
188        self.app['configuration'].name = u'University of Benin'
189        self.student.physical_clearance_date = u'January 5th, 2015'
190        self.browser.getLink("Clearance Data").click()
191        self.browser.getLink("Download clearance invitation slip").click()
192        self.assertEqual(self.browser.headers['Status'], '200 Ok')
193        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
194        path = os.path.join(samples_dir(), 'clearance_invitation_slip.pdf')
195        open(path, 'wb').write(self.browser.contents)
196        print "Sample PDF clearance_invitation_slip.pdf written to %s" % path
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 customized pdf course registration slip
369        self.browser.open(self.student_path + '/studycourse/100')
370        self.browser.getLink("Download course registration slip").click()
371        self.assertEqual(self.browser.headers['Status'], '200 Ok')
372        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
373        # Students can open the special Uniben pdf course result slip
374        self.browser.open(self.student_path + '/studycourse/100')
375        self.browser.getLink("Download course result slip").click()
376        self.assertEqual(self.browser.headers['Status'], '200 Ok')
377        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
378        # Even if course is mandatory, students can remove the course
379        self.student['studycourse']['100']['COURSE1'].mandatory = True
380        self.browser.open(self.student_path + '/studycourse/100')
381        self.browser.getLink("Edit course list").click()
382        ctrl = self.browser.getControl(name='val_id')
383        ctrl.getControl(value='COURSE1').selected = True
384        self.browser.getControl("Remove selected", index=0).click()
385        self.assertTrue('Successfully removed' in self.browser.contents)
386
387    def test_get_returning_data(self):
388        # Student is in level 100, session 2004 with verdict A
389        utils = getUtility(IStudentsUtils)
390        self.assertEqual(utils.getReturningData(self.student),(2005, 200))
391        self.student['studycourse'].current_verdict = 'C'
392        self.assertEqual(utils.getReturningData(self.student),(2005, 110))
393        self.student['studycourse'].current_verdict = 'D'
394        self.assertEqual(utils.getReturningData(self.student),(2005, 100))
395        return
396
397    def test_set_returning_data(self):
398        # Student is in level 100, session 2004 with verdict A
399        utils = getUtility(IStudentsUtils)
400
401        utils.setReturningData(self.student)
402        self.assertEqual(self.student['studycourse'].current_session, 2005)
403        self.assertEqual(self.student['studycourse'].current_level, 200)
404
405        self.student['studycourse'].current_session = 2004
406        self.student['studycourse'].current_level = 100
407        self.student['studycourse'].current_verdict = 'C'
408        utils.setReturningData(self.student)
409        self.assertEqual(self.student['studycourse'].current_session, 2005)
410        self.assertEqual(self.student['studycourse'].current_level, 110)
411
412        self.student['studycourse'].current_session = 2004
413        self.student['studycourse'].current_level = 100
414        self.student['studycourse'].current_verdict = 'D'
415        utils.setReturningData(self.student)
416        self.assertEqual(self.student['studycourse'].current_session, 2005)
417        self.assertEqual(self.student['studycourse'].current_level, 100)
418        return
419
420    def test_set_payment_details(self):
421        self.app['configuration']['2004'].gown_fee = 150.0
422        self.app['configuration']['2004'].transfer_fee = 90.0
423        self.app['configuration']['2004'].booking_fee = 150.0
424        self.app['configuration']['2004'].maint_fee = 180.0
425
426        configuration = createObject('waeup.SessionConfiguration')
427        configuration.academic_session = 2000
428        self.app['configuration'].addSessionConfiguration(configuration)
429        configuration2 = createObject('waeup.SessionConfiguration')
430        configuration2.academic_session = 2002
431        self.app['configuration'].addSessionConfiguration(configuration2)
432        configuration3 = createObject('waeup.SessionConfiguration')
433        configuration3.academic_session = 2003
434        self.app['configuration'].addSessionConfiguration(configuration3)
435        configuration4 = createObject('waeup.SessionConfiguration')
436        configuration4.academic_session = 2005
437        self.app['configuration'].addSessionConfiguration(configuration4)
438        utils = getUtility(IStudentsUtils)
439        self.student['studycourse'].entry_session = 2002
440        self.student.nationality = u'NG'
441
442        error, payment = utils.setPaymentDetails('schoolfee',
443            self.student, None, None)
444        self.assertEqual(payment, None)
445        # Student is in state 'created' and can thus not pay.
446        self.assertTrue(u'Amount could not be determined.' in error)
447
448        # Previous session must be valid.
449        error, payment = utils.setPaymentDetails('schoolfee',
450            self.student, 2000, 300)
451        self.assertEqual(payment, None)
452        self.assertTrue(u'The previous session must not fall below' in error)
453        error, payment = utils.setPaymentDetails('schoolfee',
454            self.student, 2005, 300)
455        self.assertEqual(payment, None)
456        self.assertTrue(u'This is not a previous session' in error)
457
458        # Previous session schoolfee payment; fresh and returning
459        # are distinguished by their entry_level
460        error, payment = utils.setPaymentDetails('schoolfee',
461            self.student, 2002, 300)
462        self.assertEqual(payment.amount_auth, 40000.0)
463        self.assertEqual(payment.p_session, 2002)
464        self.assertEqual(payment.p_level, 300)
465        self.assertFalse(payment.p_current)
466        error, payment = utils.setPaymentDetails('schoolfee',
467            self.student, 2003, 300)
468        self.assertEqual(payment.amount_auth, 20000.0)
469        self.assertEqual(payment.p_session, 2003)
470        self.assertEqual(payment.p_level, 300)
471        self.assertFalse(payment.p_current)
472
473        # Current schoolfee payment; fresh and returning
474        # are distinguished by their state
475        IWorkflowState(self.student).setState('cleared')
476        error, payment = utils.setPaymentDetails('schoolfee',
477            self.student, None, None)
478        self.assertEqual(payment.p_level, 100)
479        self.assertEqual(payment.p_session, 2004)
480        self.assertEqual(payment.amount_auth, 40000.0)
481        self.assertEqual(payment.p_item, u'CERT1')
482        self.assertEqual(error, None)
483        self.assertTrue(payment.p_current)
484
485        # Add penalty fee ...
486        # ... for cleared
487        self.app['configuration']['2004'].penalty_ug = 99.0
488        # ... for returning
489        self.app['configuration']['2005'].penalty_ug = 88.0
490        error, payment = utils.setPaymentDetails('schoolfee',
491            self.student, None, None)
492        self.assertEqual(payment.amount_auth, 40099.0)
493
494        IWorkflowState(self.student).setState('returning')
495
496
497        #error, payment = utils.setPaymentDetails('schoolfee',
498        #    self.student, None, None)
499        #self.assertTrue(
500        #    u'You have not yet paid your current/active session.' in error)
501        ## Ok, that means we have to add paid payment ticket first.
502        #payment = createObject('waeup.StudentOnlinePayment')
503        #payment.p_category = u'schoolfee'
504        #payment.p_session = self.student.current_session
505        #payment.p_item = u'My Certificate'
506        #payment.p_id = u'anyid'
507        #payment.p_state = u'paid'
508        #self.student['payments']['anykey'] = payment
509
510
511        error, payment = utils.setPaymentDetails('schoolfee',
512            self.student, None, None)
513        self.assertEqual(payment.p_level, 200)
514        self.assertEqual(payment.p_session, 2005)
515        self.assertEqual(payment.amount_auth, 20088.0)
516        self.assertEqual(payment.p_item, u'CERT1')
517        self.assertEqual(error, None)
518
519        # Staff members pay less.
520        self.student.is_staff = True
521        error, payment = utils.setPaymentDetails('schoolfee',
522            self.student, None, None)
523        self.assertEqual(payment.p_level, 200)
524        self.assertEqual(payment.p_session, 2005)
525        self.assertEqual(payment.amount_auth, 10088.0)
526        self.assertEqual(payment.p_item, u'CERT1')
527        self.assertEqual(error, None)
528
529        # Foreigners pay more.
530        IWorkflowState(self.student).setState('cleared')
531        self.student.is_staff = False
532        self.student.nationality = u'DE'
533        self.certificate.school_fee_3 = 60000.0
534        error, payment = utils.setPaymentDetails(
535            'schoolfee', self.student, None, None)
536        self.assertEqual(payment.p_level, 100)
537        self.assertEqual(payment.p_session, 2004)
538        self.assertEqual(payment.amount_auth, 60099.0)
539        self.assertEqual(payment.p_item, u'CERT1')
540        self.assertEqual(error, None)
541        IWorkflowState(self.student).setState('returning')
542        self.student.is_staff = False
543        self.certificate.school_fee_4 = 20000.0
544        error, payment = utils.setPaymentDetails(
545            'schoolfee', self.student, None, None)
546        self.assertEqual(payment.p_level, 200)
547        self.assertEqual(payment.p_session, 2005)
548        self.assertEqual(payment.amount_auth, 20088.0)
549        self.assertEqual(payment.p_item, u'CERT1')
550        self.assertEqual(error, None)
551
552        # In Uniben students can pay school fee in all states no matter
553        # if they are ug or pg students.
554        IWorkflowState(self.student).setState('school fee paid')
555        self.student.is_staff = False
556        self.student.nationality = u'NG'
557        self.certificate.school_fee_2 = 10000.0
558        error, payment = utils.setPaymentDetails(
559            'schoolfee', self.student, None, None)
560        self.assertEqual(payment.p_level, None)
561        self.assertEqual(payment.p_session, 2005)
562        self.assertEqual(payment.amount_auth, 10088.0)
563        self.assertEqual(payment.p_item, u'CERT1')
564        self.assertEqual(error, None)
565        IWorkflowState(self.student).setState('courses registered')
566        self.certificate.study_mode = 'special_pg_pt'
567        error, payment = utils.setPaymentDetails(
568            'schoolfee', self.student, None, None)
569        self.assertEqual(payment.p_level, None)
570        self.assertEqual(payment.p_session, 2005)
571        self.assertEqual(payment.amount_auth, 10000.0)
572        self.assertEqual(payment.p_item, u'CERT1')
573        self.assertEqual(error, None)
574        IWorkflowState(self.student).setState('courses validated')
575        error, payment = utils.setPaymentDetails(
576            'schoolfee', self.student, None, None)
577        self.assertEqual(payment.p_level, None)
578        self.assertEqual(payment.p_session, 2005)
579        self.assertEqual(payment.amount_auth, 10000.0)
580        self.assertEqual(payment.p_item, u'CERT1')
581        self.assertEqual(error, None)
582
583        error, payment = utils.setPaymentDetails('clearance',
584            self.student, None, None)
585        self.assertEqual(payment.p_level, 100)
586        self.assertEqual(payment.p_session, 2004)
587        self.assertEqual(payment.amount_auth, 45000.0)
588        self.assertEqual(payment.p_item, u'CERT1')
589        self.assertEqual(error, None)
590
591        error, payment = utils.setPaymentDetails('gown',
592            self.student, None, None)
593        self.assertEqual(payment.p_level, 100)
594        self.assertEqual(payment.p_session, 2004)
595        self.assertEqual(payment.amount_auth, 150.0)
596        self.assertEqual(payment.p_item, u'')
597        self.assertEqual(error, None)
598
599        #error, payment = utils.setPaymentDetails('hostel_maintenance',
600        #    self.student, None, None)
601        #self.assertEqual(payment.p_level, 100)
602        #self.assertEqual(payment.p_session, 2004)
603        #self.assertEqual(payment.amount_auth, 180.0)
604        #self.assertEqual(payment.p_item, u'')
605        #self.assertEqual(error, None)
606
607        #error, payment = utils.setPaymentDetails('bed_allocation',
608        #    self.student, None, None)
609        #self.assertEqual(payment.p_level, 100)
610        #self.assertEqual(payment.p_session, 2004)
611        #self.assertEqual(payment.amount_auth, 150.0)
612        #self.assertEqual(payment.p_item, u'')
613        #self.assertEqual(error, None)
614
615        error, payment = utils.setPaymentDetails('hostel_application',
616            self.student, None, None)
617        self.assertEqual(payment.p_level, 100)
618        self.assertEqual(payment.p_session, 2004)
619        self.assertEqual(payment.amount_auth, 1000.0)
620        self.assertEqual(payment.p_item, u'')
621        self.assertEqual(error, None)
622
623        payment.approve()
624        self.student['payments'][payment.p_id] = payment
625
626        error, payment = utils.setPaymentDetails('tempmaint_1',
627            self.student, None, None)
628        self.assertEqual(payment.p_level, 100)
629        self.assertEqual(payment.p_session, 2004)
630        self.assertEqual(payment.amount_auth, 8150.0)
631        self.assertEqual(payment.p_item, u'Hall 1-4 M/F Ekehuan')
632        self.assertEqual(error, None)
633
634        error, payment = utils.setPaymentDetails('tempmaint_2',
635            self.student, None, None)
636        self.assertEqual(payment.p_level, 100)
637        self.assertEqual(payment.p_session, 2004)
638        self.assertEqual(payment.amount_auth, 12650.0)
639        self.assertEqual(payment.p_item, u'Hall 5 M/F')
640        self.assertEqual(error, None)
641
642        error, payment = utils.setPaymentDetails('tempmaint_3',
643            self.student, None, None)
644        self.assertEqual(payment.p_level, 100)
645        self.assertEqual(payment.p_session, 2004)
646        self.assertEqual(payment.amount_auth, 9650.0)
647        self.assertEqual(payment.p_item, u'Clinical Hostel')
648        self.assertEqual(error, None)
649
650        error, payment = utils.setPaymentDetails('transfer',
651            self.student, None, None)
652        self.assertEqual(payment.p_level, 100)
653        self.assertEqual(payment.p_session, 2004)
654        self.assertEqual(payment.amount_auth, 90.0)
655        self.assertEqual(payment.p_item, u'')
656        self.assertEqual(error, None)
657        return
658
659    def test_edit_level_by_co(self):
660        # Create clearance officer
661        self.app['users'].addUser('mrclear', 'mrclearsecret')
662        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
663        self.app['users']['mrclear'].title = 'Carlo Pitter'
664        # Assign local ClearanceOfficer role
665        department = self.app['faculties']['fac1']['dep1']
666        prmlocal = IPrincipalRoleManager(department)
667        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
668        notify(LocalRoleSetEvent(
669            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
670        IWorkflowState(self.student).setState('clearance started')
671        # Login as clearance officer
672        self.browser.open(self.login_path)
673        self.browser.getControl(name="form.login").value = 'mrclear'
674        self.browser.getControl(name="form.password").value = 'mrclearsecret'
675        self.browser.getControl("Login").click()
676        self.assertMatches('...You logged in...', self.browser.contents)
677        # Only in state clearance requested the CO does see the
678        # 'Edit level' button ...
679        self.browser.open(self.studycourse_path)
680        self.assertFalse('Edit level' in self.browser.contents)
681        # ... and can open the edit_level view
682        self.browser.open(self.studycourse_path + '/edit_level')
683        self.assertMatches('...is locked...', self.browser.contents)
684        self.assertEqual(self.browser.url, self.studycourse_path)
685        IWorkflowInfo(self.student).fireTransition('request_clearance')
686        self.browser.open(self.studycourse_path)
687        self.assertTrue('Edit level' in self.browser.contents)
688        self.browser.getLink("Edit level").click()
689        self.browser.getControl(name="form.current_level").value = ['200']
690        self.browser.getControl("Save").click()
691        self.assertMatches('...has been saved...', self.browser.contents)
692        self.assertEqual(self.student.current_level, 200)
693
694    def test_postgraduate_student_access(self):
695        self.certificate.study_mode = 'special_pg_pt'
696        self.certificate.start_level = 700
697        self.certificate.end_level = 800
698        self.student['studycourse'].current_level = 700
699        IWorkflowState(self.student).setState('school fee paid')
700        self.browser.open(self.login_path)
701        self.browser.getControl(name="form.login").value = self.student_id
702        self.browser.getControl(name="form.password").value = 'spwd'
703        self.browser.getControl("Login").click()
704        self.assertTrue(
705            'You logged in.' in self.browser.contents)
706        # Now students can add the current study level
707        self.browser.getLink("Study Course").click()
708        self.browser.getLink("Add course list").click()
709        self.assertMatches('...Add current level 700...',
710                           self.browser.contents)
711        self.browser.getControl("Create course list now").click()
712        # A level with no course ticket was created
713        self.assertEqual(self.student['studycourse']['700'].number_of_tickets, 0)
714        self.browser.getLink("700").click()
715        self.browser.getLink("Edit course list").click()
716        self.browser.getLink("here").click()
717        self.browser.getControl(name="form.course").value = ['COURSE1']
718        # Non-final year students can't add ticket with 51 credits
719        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
720        self.browser.getControl("Add course ticket").click()
721        self.assertMatches('...Total credits exceed 50...',
722                           self.browser.contents)
723        # Final year students can't add ticket with 52 credits ...
724        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 52
725        self.student['studycourse'].certificate.end_level = 700
726        self.browser.getControl("Add course ticket").click()
727        self.assertMatches('...Total credits exceed 51...',
728                           self.browser.contents)
729        # ... but with 51 credits
730        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
731        self.browser.getControl("Add course ticket").click()
732        self.assertMatches('...Successfully added COURSE1...',
733                           self.browser.contents)
734        # Non-final year special postgraduate students can't register
735        # course lists if their total credits are 51 and thus exceed 50 ...
736        self.student['studycourse'].certificate.end_level = 800
737        self.browser.getControl("Register course list").click()
738        self.assertMatches('...Maximum credits of 50 exceeded...',
739            self.browser.contents)
740        # ... but final year students can
741        self.student['studycourse'].certificate.end_level = 700
742        self.browser.getControl("Register course list").click()
743        self.assertMatches('...Course list has been registered...',
744            self.browser.contents)
745        self.assertEqual(self.student.state, 'courses registered')
746        return
747
748    def test_login(self):
749        # If suspended_comment is set this message will be flashed instead
750        self.student.suspended_comment = u'Aetsch baetsch!'
751        self.student.suspended = True
752        self.browser.open(self.login_path)
753        self.browser.getControl(name="form.login").value = self.student_id
754        self.browser.getControl(name="form.password").value = 'spwd'
755        self.browser.getControl("Login").click()
756        # Uniben does not display suspended_comment
757        self.assertMatches(
758            '...<div class="alert alert-warning">Your account has been deactivated.</div>...',
759            self.browser.contents)
760        self.student.suspended = False
761
762    def test_activate_deactivate_buttons(self):
763        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
764        self.browser.open(self.student_path)
765        self.browser.getLink("Deactivate").click()
766        self.assertTrue(
767            'Student account has been deactivated.' in self.browser.contents)
768        self.assertTrue(
769            'Base Data (account deactivated)' in self.browser.contents)
770        self.assertTrue(self.student.suspended)
771        self.browser.getLink("Activate").click()
772        self.assertTrue(
773            'Student account has been activated.' in self.browser.contents)
774        self.assertFalse(
775            'Base Data (account deactivated)' in self.browser.contents)
776        self.assertFalse(self.student.suspended)
777        # History messages have been added ...
778        self.browser.getLink("History").click()
779        # User is undisclosed
780        self.assertTrue(
781            'Student account deactivated<br />' in self.browser.contents)
782        self.assertTrue(
783            'Student account activated<br />' in self.browser.contents)
784        # ... and actions have been logged.
785        logfile = os.path.join(
786            self.app['datacenter'].storage, 'logs', 'students.log')
787        logcontent = open(logfile).read()
788        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentDeactivatePage - '
789                        'B1000000 - account deactivated' in logcontent)
790        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentActivatePage - '
791                        'B1000000 - account activated' in logcontent)
792
793    def test_manage_upload_fpm_file(self):
794        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
795        self.browser.open(self.manage_clearance_path)
796        image = open(SAMPLE_FPM, 'rb')
797        ctrl = self.browser.getControl(name='leftthumbprintupload')
798        file_ctrl = ctrl.mech_control
799        file_ctrl.add_file(image, filename='thumbprint.fpm')
800        self.browser.getControl(
801            name='upload_leftthumbprintupload').click()
802        self.assertTrue(
803            'File finger1.fpm uploaded.' in self.browser.contents)
804        self.assertTrue(
805            'http://localhost/app/students/B1000000/finger1.fpm'
806            in self.browser.contents)
807        self.browser.getControl(
808            name='delete_leftthumbprintupload').click()
809        self.assertTrue(
810            'finger1.fpm deleted'
811            in self.browser.contents)
812
813    def test_handle_clearance_by_co(self):
814        # Create clearance officer
815        self.app['users'].addUser('mrclear', 'mrclearsecret')
816        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
817        self.app['users']['mrclear'].title = 'Carlo Pitter'
818        department = self.app['faculties']['fac1']['dep1']
819        prmlocal = IPrincipalRoleManager(department)
820        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
821        notify(LocalRoleSetEvent(
822            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
823        IWorkflowState(self.student).setState('clearance requested')
824        # Login as clearance officer
825        self.browser.open(self.login_path)
826        self.browser.getControl(name="form.login").value = 'mrclear'
827        self.browser.getControl(name="form.password").value = 'mrclearsecret'
828        self.browser.getControl("Login").click()
829        self.assertMatches('...You logged in...', self.browser.contents)
830        # CO can view the student ...
831        self.browser.open(self.clearance_path)
832        self.assertEqual(self.browser.headers['Status'], '200 Ok')
833        self.assertEqual(self.browser.url, self.clearance_path)
834        # Clearance is disabled for this session for ug students ...
835        self.browser.open(self.clearance_path)
836        self.assertFalse('Clear student' in self.browser.contents)
837        self.browser.open(self.student_path + '/clear')
838        self.assertTrue('Clearance is disabled for this session'
839            in self.browser.contents)
840        # ... but not for
841        self.certificate.study_mode = 'pg_ft'
842        self.browser.open(self.clearance_path)
843        self.assertTrue('Clear student' in self.browser.contents)
844        self.browser.open(self.student_path + '/clear')
845        self.assertTrue('Student has been cleared' in self.browser.contents)
846
847    def test_transcripts(self):
848        studylevel = createObject(u'waeup.StudentStudyLevel')
849        studylevel.level = 100
850        studylevel.level_session = 2005
851        self.student['studycourse'].entry_mode = 'ug_ft'
852        self.student['studycourse'].addStudentStudyLevel(
853            self.certificate, studylevel)
854        studylevel2 = createObject(u'waeup.StudentStudyLevel')
855        studylevel2.level = 110
856        studylevel2.level_session = 2006
857        self.student['studycourse'].addStudentStudyLevel(
858            self.certificate, studylevel2)
859        # Add second course (COURSE has been added automatically)
860        courseticket = createObject('waeup.CourseTicket')
861        courseticket.code = 'ANYCODE'
862        courseticket.title = u'Any TITLE'
863        courseticket.credits = 13
864        courseticket.score = 66
865        courseticket.semester = 1
866        courseticket.dcode = u'ANYDCODE'
867        courseticket.fcode = u'ANYFCODE'
868        self.student['studycourse']['110']['COURSE2'] = courseticket
869        self.student['studycourse']['100']['COURSE1'].score = 55
870        self.assertEqual(self.student['studycourse']['100'].gpa_params_rectified[0], 3.0)
871        self.assertEqual(self.student['studycourse']['110'].gpa_params_rectified[0], 4.0)
872        # Get transcript data
873        td = self.student['studycourse'].getTranscriptData()
874        self.assertEqual(td[0][0]['level_key'], '100')
875        self.assertEqual(td[0][0]['sgpa'], 3.0)
876        self.assertEqual(td[0][0]['level'].level, 100)
877        self.assertEqual(td[0][0]['level'].level_session, 2005)
878        self.assertEqual(td[0][0]['tickets_1'][0].code, 'COURSE1')
879        self.assertEqual(td[0][1]['level_key'], '110')
880        self.assertEqual(td[0][1]['sgpa'], 4.0)
881        self.assertEqual(td[0][1]['level'].level, 110)
882        self.assertEqual(td[0][1]['level'].level_session, 2006)
883        self.assertEqual(td[0][1]['tickets_1'][0].code, 'ANYCODE')
884        self.assertEqual(td[1], 3.57)
885        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
886        self.browser.open(self.student_path + '/studycourse/transcript')
887        self.assertEqual(self.browser.headers['Status'], '200 Ok')
888        self.assertTrue('Transcript' in self.browser.contents)
889        # Officers can open the pdf transcript
890        self.browser.open(self.student_path + '/studycourse/transcript.pdf')
891        self.assertEqual(self.browser.headers['Status'], '200 Ok')
892        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
893        path = os.path.join(samples_dir(), 'transcript.pdf')
894        open(path, 'wb').write(self.browser.contents)
895        print "Sample PDF transcript.pdf written to %s" % path
Note: See TracBrowser for help on using the repository browser.