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

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

Do only provide invitation letter if physical_clearance_date is set and student is in state 'clearance requested'.

  • Property svn:keywords set to Id
File size: 40.2 KB
Line 
1## $Id: test_browser.py 12122 2014-12-03 06:43:26Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import os
19import shutil
20import tempfile
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        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
104    def test_student_access(self):
105        # Students can edit clearance data
106        IWorkflowState(self.student).setState('clearance started')
107        self.student.clearance_locked = False
108        self.student.nationality = u'NG'
109        file_store = getUtility(IExtFileStore)
110        self.browser.open(self.login_path)
111        self.browser.getControl(name="form.login").value = self.student_id
112        self.browser.getControl(name="form.password").value = 'spwd'
113        self.browser.getControl("Login").click()
114        self.browser.open(self.edit_clearance_path)
115        # UG students can't edit date_of_birth, nationality and lga
116        self.assertFalse('form.date_of_birth' in self.browser.contents)
117        self.assertFalse('form.nationality' in self.browser.contents)
118        self.assertFalse('form.lga' in self.browser.contents)
119        # Clearance can only be requested if all required documents
120        # have been uploaded.
121        self.browser.getControl("Save and request clearance").click()
122        self.assertTrue('No birth certificate uploaded'
123            in self.browser.contents)
124        birth_certificate = 'My birth certificate'
125        file_id = IFileStoreNameChooser(self.student).chooseName(
126            attr="birth_certificate.jpg")
127        file_store.createFile(file_id, StringIO(birth_certificate))
128        self.browser.open(self.edit_clearance_path)
129        self.browser.getControl("Save and request clearance").click()
130
131        self.assertTrue('No guarantor/referee letter uploaded'
132            in self.browser.contents)
133        ref_let = 'My ref let'
134        file_id = IFileStoreNameChooser(self.student).chooseName(
135            attr="ref_let.jpg")
136        file_store.createFile(file_id, StringIO(ref_let))
137        self.browser.open(self.edit_clearance_path)
138        self.browser.getControl("Save and request clearance").click()
139
140        self.assertTrue('No acceptance letter uploaded'
141            in self.browser.contents)
142        acc_let = 'My acc let'
143        file_id = IFileStoreNameChooser(self.student).chooseName(
144            attr="acc_let.jpg")
145        file_store.createFile(file_id, StringIO(acc_let))
146        self.browser.open(self.edit_clearance_path)
147        self.browser.getControl("Save and request clearance").click()
148
149        self.assertTrue('No first sitting result uploaded'
150            in self.browser.contents)
151        fst_sit_scan = 'My first sitting result'
152        file_id = IFileStoreNameChooser(self.student).chooseName(
153            attr="fst_sit_scan.jpg")
154        file_store.createFile(file_id, StringIO(fst_sit_scan))
155        self.browser.open(self.edit_clearance_path)
156        self.browser.getControl("Save and request clearance").click()
157
158        #self.assertTrue('No second sitting result uploaded'
159        #    in self.browser.contents)
160        #scd_sit_scan = 'My second sitting result'
161        #file_id = IFileStoreNameChooser(self.student).chooseName(
162        #    attr="scd_sit_scan.jpg")
163        #file_store.createFile(file_id, StringIO(scd_sit_scan))
164        #self.browser.open(self.edit_clearance_path)
165        #self.browser.getControl("Save and request clearance").click()
166
167        self.assertTrue('No affidavit of non-membership of secret cults uploaded'
168            in self.browser.contents)
169        secr_cults = 'My non-membership scan'
170        file_id = IFileStoreNameChooser(self.student).chooseName(
171            attr="secr_cults.jpg")
172        file_store.createFile(file_id, StringIO(secr_cults))
173        # Clearance invitation letter is not yet available
174        self.browser.open(self.clearance_path)
175        self.assertFalse('invitation slip' in self.browser.contents)
176        self.browser.open(self.student_path + '/clearance_invitation_slip.pdf')
177        self.assertTrue('Forbidden' in self.browser.contents)
178        self.browser.open(self.edit_clearance_path)
179        self.browser.getControl("Save and request clearance").click()
180        self.assertTrue('Clearance has been requested'
181            in self.browser.contents)
182        # Now student can export physical_clearance.slip
183        self.app['configuration'].name = u'University of Benin'
184        self.student.physical_clearance_date = u'January 5th, 2015'
185        self.browser.getLink("Clearance Data").click()
186        self.browser.getLink("Download clearance invitation slip").click()
187        self.assertEqual(self.browser.headers['Status'], '200 Ok')
188        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
189        path = os.path.join(samples_dir(), 'clearance_invitation_slip.pdf')
190        open(path, 'wb').write(self.browser.contents)
191        print "Sample PDF clearance_invitation_slip.pdf written to %s" % path
192
193    def test_manage_payments(self):
194        # Add missing configuration data
195        self.app['configuration']['2004'].gown_fee = 150.0
196        self.app['configuration']['2004'].transfer_fee = 90.0
197        #self.app['configuration']['2004'].clearance_fee = 120.0
198        self.app['configuration']['2004'].booking_fee = 150.0
199        self.app['configuration']['2004'].maint_fee = 180.0
200
201        # Managers can add online payment tickets
202        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
203        self.browser.open(self.payments_path)
204        self.browser.getLink("Add current session payment ticket").click()
205        self.browser.getControl("Create ticket").click()
206        self.assertMatches('...Amount could not be determined...',
207                           self.browser.contents)
208        IWorkflowState(self.student).setState('cleared')
209        self.student.nationality = u'NG'
210        self.browser.open(self.payments_path + '/addop')
211        self.browser.getControl(name="form.p_category").value = ['schoolfee']
212        self.browser.getControl("Create ticket").click()
213        self.assertMatches('...ticket created...',
214                           self.browser.contents)
215        ctrl = self.browser.getControl(name='val_id')
216        value = ctrl.options[0]
217        self.browser.getLink(value).click()
218        self.assertMatches('...Amount Authorized...',
219                           self.browser.contents)
220        # Managers can open payment slip
221        self.browser.getLink("Download payment slip").click()
222        self.assertEqual(self.browser.headers['Status'], '200 Ok')
223        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
224        # Set ticket paid
225        ticket = self.student['payments'].items()[0][1]
226        ticket.p_state = 'paid'
227        self.browser.open(self.payments_path + '/addop')
228        self.browser.getControl(name="form.p_category").value = ['schoolfee']
229        self.browser.getControl("Create ticket").click()
230        self.assertMatches('...This type of payment has already been made...',
231                           self.browser.contents)
232        # Remove all payments so that we can add a school fee payment again
233        keys = [i for i in self.student['payments'].keys()]
234        for payment in keys:
235            del self.student['payments'][payment]
236        self.browser.open(self.payments_path + '/addop')
237        self.browser.getControl(name="form.p_category").value = ['schoolfee']
238        self.browser.getControl("Create ticket").click()
239        self.assertMatches('...ticket created...',
240                           self.browser.contents)
241        schoolfee_ticket = self.student['payments'].values()[0]
242        self.browser.open(self.payments_path + '/addop')
243        self.browser.getControl(name="form.p_category").value = ['gown']
244        self.browser.getControl("Create ticket").click()
245        self.assertMatches('...ticket created...',
246                           self.browser.contents)
247        self.browser.open(self.payments_path + '/addop')
248        self.browser.getControl(
249            name="form.p_category").value = ['tempmaint_1']
250        self.browser.getControl("Create ticket").click()
251        self.assertMatches('...ticket created...',
252                           self.browser.contents)
253        self.browser.open(self.payments_path + '/addop')
254        self.browser.getControl(
255            name="form.p_category").value = ['tempmaint_2']
256        self.browser.getControl("Create ticket").click()
257        self.assertMatches('...ticket created...',
258                           self.browser.contents)
259        self.browser.open(self.payments_path + '/addop')
260        self.browser.getControl(
261            name="form.p_category").value = ['tempmaint_3']
262        self.browser.getControl("Create ticket").click()
263        self.assertMatches('...ticket created...',
264                           self.browser.contents)
265        self.browser.open(self.payments_path + '/addop')
266        # We can't test clearance payment ticket creation at the moment,
267        # since Uniben decided to deactivate clearance for ug students.
268        #self.browser.getControl(name="form.p_category").value = ['clearance']
269        #self.browser.getControl("Create ticket").click()
270        #self.assertMatches('...ticket created...',
271        #                   self.browser.contents)
272        self.browser.open(self.payments_path + '/addop')
273        self.browser.getControl(name="form.p_category").value = ['schoolfee']
274        self.browser.getControl("Create ticket").click()
275        self.assertMatches('...ticket created...',
276                           self.browser.contents)
277        # In state returning we can add a new school fee ticket since
278        # p_session and p_level is different
279        IWorkflowState(self.student).setState('returning')
280        self.browser.open(self.payments_path + '/addop')
281        self.browser.getControl(name="form.p_category").value = ['schoolfee']
282        self.browser.getControl("Create ticket").click()
283        # Uups, we forgot to add a session configuration for next session
284        self.assertMatches('...Session configuration object is not...',
285                           self.browser.contents)
286        configuration = createObject('waeup.SessionConfiguration')
287        configuration.academic_session = 2005
288        self.app['configuration'].addSessionConfiguration(configuration)
289        self.browser.open(self.payments_path + '/addop')
290        self.browser.getControl(name="form.p_category").value = ['schoolfee']
291        self.browser.getControl("Create ticket").click()
292
293
294        #self.assertMatches('...You have not yet paid your current/active session...',
295        #                   self.browser.contents)
296        ## Ok, let's pay the first schoolfee ticket.
297        #schoolfee_ticket.approve()
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
302
303        self.assertMatches('...ticket created...',
304                           self.browser.contents)
305        # In state admitted school fee can't be determined
306        IWorkflowState(self.student).setState('admitted')
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        self.assertMatches('...Amount could not be determined...',
311                           self.browser.contents)
312
313        # If the session configuration doesn't exist an error message will
314        # be shown. No other requirement is being checked.
315        del self.app['configuration']['2004']
316        self.browser.open(self.payments_path)
317        self.browser.getLink("Add current session payment ticket").click()
318        self.browser.getControl("Create ticket").click()
319        self.assertMatches('...Session configuration object is not...',
320                           self.browser.contents)
321
322    def test_student_course_registration(self):
323        # Uniben students see grade instead of score on all level pages
324        # and on course ticket page.
325        IWorkflowState(self.student).setState('school fee paid')
326        self.browser.open(self.login_path)
327        self.browser.getControl(name="form.login").value = self.student_id
328        self.browser.getControl(name="form.password").value = 'spwd'
329        self.browser.getControl("Login").click()
330        # Now students can add the current study level
331        self.browser.getLink("Study Course").click()
332        self.browser.getLink("Add course list").click()
333        self.assertMatches('...Add current level 100 (Year 1)...',
334                           self.browser.contents)
335        self.browser.getControl("Create course list now").click()
336        # A level with one course ticket was created
337        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 1)
338        self.student['studycourse']['100']['COURSE1'].score = 55
339        self.browser.getLink("100").click()
340        # GPA has been properly calculated
341        self.assertEqual(self.student['studycourse']['100'].gpa_params[0], 3.0)
342        # Score is not shown but grade
343        self.assertTrue('<th>Grade</th>' in self.browser.contents)
344        self.assertFalse('<th>Score</th>' in self.browser.contents)
345        self.browser.getLink("Edit course list").click()
346        self.assertTrue('<th>Grade</th>' in self.browser.contents)
347        self.assertFalse('<th>Score</th>' in self.browser.contents)
348        self.browser.getLink("COURSE1").click()
349        self.assertFalse('Score' in self.browser.contents)
350        # Students can open the customized pdf course registration slip
351        self.browser.open(self.student_path + '/studycourse/100')
352        self.browser.getLink("Download course registration slip").click()
353        self.assertEqual(self.browser.headers['Status'], '200 Ok')
354        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
355        # Students can open the special Uniben pdf course result slip
356        self.browser.open(self.student_path + '/studycourse/100')
357        self.browser.getLink("Download course result slip").click()
358        self.assertEqual(self.browser.headers['Status'], '200 Ok')
359        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
360        # Even if course is mandatory, students can remove the course
361        self.student['studycourse']['100']['COURSE1'].mandatory = True
362        self.browser.open(self.student_path + '/studycourse/100')
363        self.browser.getLink("Edit course list").click()
364        ctrl = self.browser.getControl(name='val_id')
365        ctrl.getControl(value='COURSE1').selected = True
366        self.browser.getControl("Remove selected", index=0).click()
367        self.assertTrue('Successfully removed' in self.browser.contents)
368
369    def test_get_returning_data(self):
370        # Student is in level 100, session 2004 with verdict A
371        utils = getUtility(IStudentsUtils)
372        self.assertEqual(utils.getReturningData(self.student),(2005, 200))
373        self.student['studycourse'].current_verdict = 'C'
374        self.assertEqual(utils.getReturningData(self.student),(2005, 110))
375        self.student['studycourse'].current_verdict = 'D'
376        self.assertEqual(utils.getReturningData(self.student),(2005, 100))
377        return
378
379    def test_set_returning_data(self):
380        # Student is in level 100, session 2004 with verdict A
381        utils = getUtility(IStudentsUtils)
382
383        utils.setReturningData(self.student)
384        self.assertEqual(self.student['studycourse'].current_session, 2005)
385        self.assertEqual(self.student['studycourse'].current_level, 200)
386
387        self.student['studycourse'].current_session = 2004
388        self.student['studycourse'].current_level = 100
389        self.student['studycourse'].current_verdict = 'C'
390        utils.setReturningData(self.student)
391        self.assertEqual(self.student['studycourse'].current_session, 2005)
392        self.assertEqual(self.student['studycourse'].current_level, 110)
393
394        self.student['studycourse'].current_session = 2004
395        self.student['studycourse'].current_level = 100
396        self.student['studycourse'].current_verdict = 'D'
397        utils.setReturningData(self.student)
398        self.assertEqual(self.student['studycourse'].current_session, 2005)
399        self.assertEqual(self.student['studycourse'].current_level, 100)
400        return
401
402    def test_set_payment_details(self):
403        self.app['configuration']['2004'].gown_fee = 150.0
404        self.app['configuration']['2004'].transfer_fee = 90.0
405        self.app['configuration']['2004'].booking_fee = 150.0
406        self.app['configuration']['2004'].maint_fee = 180.0
407
408        configuration = createObject('waeup.SessionConfiguration')
409        configuration.academic_session = 2000
410        self.app['configuration'].addSessionConfiguration(configuration)
411        configuration2 = createObject('waeup.SessionConfiguration')
412        configuration2.academic_session = 2002
413        self.app['configuration'].addSessionConfiguration(configuration2)
414        configuration3 = createObject('waeup.SessionConfiguration')
415        configuration3.academic_session = 2003
416        self.app['configuration'].addSessionConfiguration(configuration3)
417        configuration4 = createObject('waeup.SessionConfiguration')
418        configuration4.academic_session = 2005
419        self.app['configuration'].addSessionConfiguration(configuration4)
420        utils = getUtility(IStudentsUtils)
421        self.student['studycourse'].entry_session = 2002
422        self.student.nationality = u'NG'
423
424        error, payment = utils.setPaymentDetails('schoolfee',
425            self.student, None, None)
426        self.assertEqual(payment, None)
427        # Student is in state 'created' and can thus not pay.
428        self.assertTrue(u'Amount could not be determined.' in error)
429
430        # Previous session must be valid.
431        error, payment = utils.setPaymentDetails('schoolfee',
432            self.student, 2000, 300)
433        self.assertEqual(payment, None)
434        self.assertTrue(u'The previous session must not fall below' in error)
435        error, payment = utils.setPaymentDetails('schoolfee',
436            self.student, 2005, 300)
437        self.assertEqual(payment, None)
438        self.assertTrue(u'This is not a previous session' in error)
439
440        # Previous session schoolfee payment; fresh and returning
441        # are distinguished by their entry_level
442        error, payment = utils.setPaymentDetails('schoolfee',
443            self.student, 2002, 300)
444        self.assertEqual(payment.amount_auth, 40000.0)
445        self.assertEqual(payment.p_session, 2002)
446        self.assertEqual(payment.p_level, 300)
447        self.assertFalse(payment.p_current)
448        error, payment = utils.setPaymentDetails('schoolfee',
449            self.student, 2003, 300)
450        self.assertEqual(payment.amount_auth, 20000.0)
451        self.assertEqual(payment.p_session, 2003)
452        self.assertEqual(payment.p_level, 300)
453        self.assertFalse(payment.p_current)
454
455        # Current schoolfee payment; fresh and returning
456        # are distinguished by their state
457        IWorkflowState(self.student).setState('cleared')
458        error, payment = utils.setPaymentDetails('schoolfee',
459            self.student, None, None)
460        self.assertEqual(payment.p_level, 100)
461        self.assertEqual(payment.p_session, 2004)
462        self.assertEqual(payment.amount_auth, 40000.0)
463        self.assertEqual(payment.p_item, u'CERT1')
464        self.assertEqual(error, None)
465        self.assertTrue(payment.p_current)
466
467        # Add penalty fee ...
468        # ... for cleared
469        self.app['configuration']['2004'].penalty_ug = 99.0
470        # ... for returning
471        self.app['configuration']['2005'].penalty_ug = 88.0
472        error, payment = utils.setPaymentDetails('schoolfee',
473            self.student, None, None)
474        self.assertEqual(payment.amount_auth, 40099.0)
475
476        IWorkflowState(self.student).setState('returning')
477
478
479        #error, payment = utils.setPaymentDetails('schoolfee',
480        #    self.student, None, None)
481        #self.assertTrue(
482        #    u'You have not yet paid your current/active session.' in error)
483        ## Ok, that means we have to add paid payment ticket first.
484        #payment = createObject('waeup.StudentOnlinePayment')
485        #payment.p_category = u'schoolfee'
486        #payment.p_session = self.student.current_session
487        #payment.p_item = u'My Certificate'
488        #payment.p_id = u'anyid'
489        #payment.p_state = u'paid'
490        #self.student['payments']['anykey'] = payment
491
492
493        error, payment = utils.setPaymentDetails('schoolfee',
494            self.student, None, None)
495        self.assertEqual(payment.p_level, 200)
496        self.assertEqual(payment.p_session, 2005)
497        self.assertEqual(payment.amount_auth, 20088.0)
498        self.assertEqual(payment.p_item, u'CERT1')
499        self.assertEqual(error, None)
500
501        # Staff members pay less.
502        self.student.is_staff = True
503        error, payment = utils.setPaymentDetails('schoolfee',
504            self.student, None, None)
505        self.assertEqual(payment.p_level, 200)
506        self.assertEqual(payment.p_session, 2005)
507        self.assertEqual(payment.amount_auth, 10088.0)
508        self.assertEqual(payment.p_item, u'CERT1')
509        self.assertEqual(error, None)
510
511        # Foreigners pay more.
512        IWorkflowState(self.student).setState('cleared')
513        self.student.is_staff = False
514        self.student.nationality = u'DE'
515        self.certificate.school_fee_3 = 60000.0
516        error, payment = utils.setPaymentDetails(
517            'schoolfee', self.student, None, None)
518        self.assertEqual(payment.p_level, 100)
519        self.assertEqual(payment.p_session, 2004)
520        self.assertEqual(payment.amount_auth, 60099.0)
521        self.assertEqual(payment.p_item, u'CERT1')
522        self.assertEqual(error, None)
523        IWorkflowState(self.student).setState('returning')
524        self.student.is_staff = False
525        self.certificate.school_fee_4 = 20000.0
526        error, payment = utils.setPaymentDetails(
527            'schoolfee', self.student, None, None)
528        self.assertEqual(payment.p_level, 200)
529        self.assertEqual(payment.p_session, 2005)
530        self.assertEqual(payment.amount_auth, 20088.0)
531        self.assertEqual(payment.p_item, u'CERT1')
532        self.assertEqual(error, None)
533
534        # In Uniben students can pay school fee in all states no matter
535        # if they are ug or pg students.
536        IWorkflowState(self.student).setState('school fee paid')
537        self.student.is_staff = False
538        self.student.nationality = u'NG'
539        self.certificate.school_fee_2 = 10000.0
540        error, payment = utils.setPaymentDetails(
541            'schoolfee', self.student, None, None)
542        self.assertEqual(payment.p_level, None)
543        self.assertEqual(payment.p_session, 2005)
544        self.assertEqual(payment.amount_auth, 10088.0)
545        self.assertEqual(payment.p_item, u'CERT1')
546        self.assertEqual(error, None)
547        IWorkflowState(self.student).setState('courses registered')
548        self.certificate.study_mode = 'special_pg_pt'
549        error, payment = utils.setPaymentDetails(
550            'schoolfee', self.student, None, None)
551        self.assertEqual(payment.p_level, None)
552        self.assertEqual(payment.p_session, 2005)
553        self.assertEqual(payment.amount_auth, 10000.0)
554        self.assertEqual(payment.p_item, u'CERT1')
555        self.assertEqual(error, None)
556        IWorkflowState(self.student).setState('courses validated')
557        error, payment = utils.setPaymentDetails(
558            'schoolfee', self.student, None, None)
559        self.assertEqual(payment.p_level, None)
560        self.assertEqual(payment.p_session, 2005)
561        self.assertEqual(payment.amount_auth, 10000.0)
562        self.assertEqual(payment.p_item, u'CERT1')
563        self.assertEqual(error, None)
564
565        error, payment = utils.setPaymentDetails('clearance',
566            self.student, None, None)
567        self.assertEqual(payment.p_level, 100)
568        self.assertEqual(payment.p_session, 2004)
569        self.assertEqual(payment.amount_auth, 45000.0)
570        self.assertEqual(payment.p_item, u'CERT1')
571        self.assertEqual(error, None)
572
573        error, payment = utils.setPaymentDetails('gown',
574            self.student, None, None)
575        self.assertEqual(payment.p_level, 100)
576        self.assertEqual(payment.p_session, 2004)
577        self.assertEqual(payment.amount_auth, 150.0)
578        self.assertEqual(payment.p_item, u'')
579        self.assertEqual(error, None)
580
581        error, payment = utils.setPaymentDetails('hostel_maintenance',
582            self.student, None, None)
583        self.assertEqual(payment.p_level, 100)
584        self.assertEqual(payment.p_session, 2004)
585        self.assertEqual(payment.amount_auth, 180.0)
586        self.assertEqual(payment.p_item, u'')
587        self.assertEqual(error, None)
588
589        error, payment = utils.setPaymentDetails('bed_allocation',
590            self.student, None, None)
591        self.assertEqual(payment.p_level, 100)
592        self.assertEqual(payment.p_session, 2004)
593        self.assertEqual(payment.amount_auth, 150.0)
594        self.assertEqual(payment.p_item, u'')
595        self.assertEqual(error, None)
596
597        error, payment = utils.setPaymentDetails('tempmaint_1',
598            self.student, None, None)
599        self.assertEqual(payment.p_level, 100)
600        self.assertEqual(payment.p_session, 2004)
601        self.assertEqual(payment.amount_auth, 8150.0)
602        self.assertEqual(payment.p_item, u'Hall 1-4 M/F Ekehuan')
603        self.assertEqual(error, None)
604
605        error, payment = utils.setPaymentDetails('tempmaint_2',
606            self.student, None, None)
607        self.assertEqual(payment.p_level, 100)
608        self.assertEqual(payment.p_session, 2004)
609        self.assertEqual(payment.amount_auth, 12650.0)
610        self.assertEqual(payment.p_item, u'Hall 5 M/F')
611        self.assertEqual(error, None)
612
613        error, payment = utils.setPaymentDetails('tempmaint_3',
614            self.student, None, None)
615        self.assertEqual(payment.p_level, 100)
616        self.assertEqual(payment.p_session, 2004)
617        self.assertEqual(payment.amount_auth, 9650.0)
618        self.assertEqual(payment.p_item, u'Clinical Hostel')
619        self.assertEqual(error, None)
620
621        error, payment = utils.setPaymentDetails('transfer',
622            self.student, None, None)
623        self.assertEqual(payment.p_level, 100)
624        self.assertEqual(payment.p_session, 2004)
625        self.assertEqual(payment.amount_auth, 90.0)
626        self.assertEqual(payment.p_item, u'')
627        self.assertEqual(error, None)
628        return
629
630    def test_edit_level_by_co(self):
631        # Create clearance officer
632        self.app['users'].addUser('mrclear', 'mrclearsecret')
633        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
634        self.app['users']['mrclear'].title = 'Carlo Pitter'
635        # Assign local ClearanceOfficer role
636        department = self.app['faculties']['fac1']['dep1']
637        prmlocal = IPrincipalRoleManager(department)
638        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
639        notify(LocalRoleSetEvent(
640            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
641        IWorkflowState(self.student).setState('clearance started')
642        # Login as clearance officer
643        self.browser.open(self.login_path)
644        self.browser.getControl(name="form.login").value = 'mrclear'
645        self.browser.getControl(name="form.password").value = 'mrclearsecret'
646        self.browser.getControl("Login").click()
647        self.assertMatches('...You logged in...', self.browser.contents)
648        # Only in state clearance requested the CO does see the
649        # 'Edit level' button ...
650        self.browser.open(self.studycourse_path)
651        self.assertFalse('Edit level' in self.browser.contents)
652        # ... and can open the edit_level view
653        self.browser.open(self.studycourse_path + '/edit_level')
654        self.assertMatches('...is locked...', self.browser.contents)
655        self.assertEqual(self.browser.url, self.studycourse_path)
656        IWorkflowInfo(self.student).fireTransition('request_clearance')
657        self.browser.open(self.studycourse_path)
658        self.assertTrue('Edit level' in self.browser.contents)
659        self.browser.getLink("Edit level").click()
660        self.browser.getControl(name="form.current_level").value = ['200']
661        self.browser.getControl("Save").click()
662        self.assertMatches('...has been saved...', self.browser.contents)
663        self.assertEqual(self.student.current_level, 200)
664
665    def test_postgraduate_student_access(self):
666        self.certificate.study_mode = 'special_pg_pt'
667        self.certificate.start_level = 700
668        self.certificate.end_level = 800
669        self.student['studycourse'].current_level = 700
670        IWorkflowState(self.student).setState('school fee paid')
671        self.browser.open(self.login_path)
672        self.browser.getControl(name="form.login").value = self.student_id
673        self.browser.getControl(name="form.password").value = 'spwd'
674        self.browser.getControl("Login").click()
675        self.assertTrue(
676            'You logged in.' in self.browser.contents)
677        # Now students can add the current study level
678        self.browser.getLink("Study Course").click()
679        self.browser.getLink("Add course list").click()
680        self.assertMatches('...Add current level 700...',
681                           self.browser.contents)
682        self.browser.getControl("Create course list now").click()
683        # A level with no course ticket was created
684        self.assertEqual(self.student['studycourse']['700'].number_of_tickets, 0)
685        self.browser.getLink("700").click()
686        self.browser.getLink("Edit course list").click()
687        self.browser.getLink("here").click()
688        self.browser.getControl(name="form.course").value = ['COURSE1']
689        # Non-final year students can't add ticket with 51 credits
690        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
691        self.browser.getControl("Add course ticket").click()
692        self.assertMatches('...Total credits exceed 50...',
693                           self.browser.contents)
694        # Final year students can't add ticket with 52 credits ...
695        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 52
696        self.student['studycourse'].certificate.end_level = 700
697        self.browser.getControl("Add course ticket").click()
698        self.assertMatches('...Total credits exceed 51...',
699                           self.browser.contents)
700        # ... but with 51 credits
701        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
702        self.browser.getControl("Add course ticket").click()
703        self.assertMatches('...Successfully added COURSE1...',
704                           self.browser.contents)
705        # Non-final year special postgraduate students can't register
706        # course lists if their total credits are 51 and thus exceed 50 ...
707        self.student['studycourse'].certificate.end_level = 800
708        self.browser.getControl("Register course list").click()
709        self.assertMatches('...Maximum credits of 50 exceeded...',
710            self.browser.contents)
711        # ... but final year students can
712        self.student['studycourse'].certificate.end_level = 700
713        self.browser.getControl("Register course list").click()
714        self.assertMatches('...Course list has been registered...',
715            self.browser.contents)
716        self.assertEqual(self.student.state, 'courses registered')
717        return
718
719    def test_login(self):
720        # If suspended_comment is set this message will be flashed instead
721        self.student.suspended_comment = u'Aetsch baetsch!'
722        self.student.suspended = True
723        self.browser.open(self.login_path)
724        self.browser.getControl(name="form.login").value = self.student_id
725        self.browser.getControl(name="form.password").value = 'spwd'
726        self.browser.getControl("Login").click()
727        # Uniben does not display suspended_comment
728        self.assertMatches(
729            '...<div class="alert alert-warning">Your account has been deactivated.</div>...',
730            self.browser.contents)
731        self.student.suspended = False
732
733    def test_activate_deactivate_buttons(self):
734        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
735        self.browser.open(self.student_path)
736        self.browser.getLink("Deactivate").click()
737        self.assertTrue(
738            'Student account has been deactivated.' in self.browser.contents)
739        self.assertTrue(
740            'Base Data (account deactivated)' in self.browser.contents)
741        self.assertTrue(self.student.suspended)
742        self.browser.getLink("Activate").click()
743        self.assertTrue(
744            'Student account has been activated.' in self.browser.contents)
745        self.assertFalse(
746            'Base Data (account deactivated)' in self.browser.contents)
747        self.assertFalse(self.student.suspended)
748        # History messages have been added ...
749        self.browser.getLink("History").click()
750        # User is undisclosed
751        self.assertTrue(
752            'Student account deactivated<br />' in self.browser.contents)
753        self.assertTrue(
754            'Student account activated<br />' in self.browser.contents)
755        # ... and actions have been logged.
756        logfile = os.path.join(
757            self.app['datacenter'].storage, 'logs', 'students.log')
758        logcontent = open(logfile).read()
759        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentDeactivatePage - '
760                        'B1000000 - account deactivated' in logcontent)
761        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentActivatePage - '
762                        'B1000000 - account activated' in logcontent)
763
764    def test_manage_upload_fpm_file(self):
765        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
766        self.browser.open(self.manage_clearance_path)
767        image = open(SAMPLE_FPM, 'rb')
768        ctrl = self.browser.getControl(name='leftthumbprintupload')
769        file_ctrl = ctrl.mech_control
770        file_ctrl.add_file(image, filename='thumbprint.fpm')
771        self.browser.getControl(
772            name='upload_leftthumbprintupload').click()
773        self.assertTrue(
774            'File finger1.fpm uploaded.' in self.browser.contents)
775        self.assertTrue(
776            'http://localhost/app/students/B1000000/finger1.fpm'
777            in self.browser.contents)
778        self.browser.getControl(
779            name='delete_leftthumbprintupload').click()
780        self.assertTrue(
781            'finger1.fpm deleted'
782            in self.browser.contents)
783
784    def test_handle_clearance_by_co(self):
785        # Create clearance officer
786        self.app['users'].addUser('mrclear', 'mrclearsecret')
787        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
788        self.app['users']['mrclear'].title = 'Carlo Pitter'
789        department = self.app['faculties']['fac1']['dep1']
790        prmlocal = IPrincipalRoleManager(department)
791        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
792        notify(LocalRoleSetEvent(
793            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
794        IWorkflowState(self.student).setState('clearance requested')
795        # Login as clearance officer
796        self.browser.open(self.login_path)
797        self.browser.getControl(name="form.login").value = 'mrclear'
798        self.browser.getControl(name="form.password").value = 'mrclearsecret'
799        self.browser.getControl("Login").click()
800        self.assertMatches('...You logged in...', self.browser.contents)
801        # CO can view the student ...
802        self.browser.open(self.clearance_path)
803        self.assertEqual(self.browser.headers['Status'], '200 Ok')
804        self.assertEqual(self.browser.url, self.clearance_path)
805        # Clearance is disabled for this session for ug students ...
806        self.browser.open(self.clearance_path)
807        self.assertFalse('Clear student' in self.browser.contents)
808        self.browser.open(self.student_path + '/clear')
809        self.assertTrue('Clearance is disabled for this session'
810            in self.browser.contents)
811        # ... but not for
812        self.certificate.study_mode = 'pg_ft'
813        self.browser.open(self.clearance_path)
814        self.assertTrue('Clear student' in self.browser.contents)
815        self.browser.open(self.student_path + '/clear')
816        self.assertTrue('Student has been cleared' in self.browser.contents)
Note: See TracBrowser for help on using the repository browser.