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

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

Students are only allowed to download course registration slips if they are
in state 'registered' and their current level corresponds with the course
registration level.

  • Property svn:keywords set to Id
File size: 44.5 KB
Line 
1## $Id: test_browser.py 12855 2015-04-13 14:55:28Z 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 special Uniben pdf course result slip
369        self.browser.open(self.student_path + '/studycourse/100')
370        self.browser.getLink("Download course result slip").click()
371        self.assertEqual(self.browser.headers['Status'], '200 Ok')
372        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
373        # Even if course is mandatory, students can remove the course
374        self.student['studycourse']['100']['COURSE1'].mandatory = True
375        self.browser.open(self.student_path + '/studycourse/100')
376        self.browser.getLink("Edit course list").click()
377        ctrl = self.browser.getControl(name='val_id')
378        ctrl.getControl(value='COURSE1').selected = True
379        self.browser.getControl("Remove selected", index=0).click()
380        self.assertTrue('Successfully removed' in self.browser.contents)
381        # Students can open the customized pdf course registration slip
382        # if they have registered their course list
383        self.browser.open(
384            self.student_path + '/studycourse/100/course_registration_slip.pdf')
385        self.assertTrue('Forbidden' in self.browser.contents)
386        IWorkflowState(self.student).setState('courses registered')
387        self.browser.open(self.student_path + '/studycourse/100')
388        self.browser.getLink("Download course registration slip").click()
389        self.assertEqual(self.browser.headers['Status'], '200 Ok')
390        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
391
392    def test_get_returning_data(self):
393        # Student is in level 100, session 2004 with verdict A
394        utils = getUtility(IStudentsUtils)
395        self.assertEqual(utils.getReturningData(self.student),(2005, 200))
396        self.student['studycourse'].current_verdict = 'C'
397        self.assertEqual(utils.getReturningData(self.student),(2005, 110))
398        self.student['studycourse'].current_verdict = 'D'
399        self.assertEqual(utils.getReturningData(self.student),(2005, 100))
400        return
401
402    def test_set_returning_data(self):
403        # Student is in level 100, session 2004 with verdict A
404        utils = getUtility(IStudentsUtils)
405
406        utils.setReturningData(self.student)
407        self.assertEqual(self.student['studycourse'].current_session, 2005)
408        self.assertEqual(self.student['studycourse'].current_level, 200)
409
410        self.student['studycourse'].current_session = 2004
411        self.student['studycourse'].current_level = 100
412        self.student['studycourse'].current_verdict = 'C'
413        utils.setReturningData(self.student)
414        self.assertEqual(self.student['studycourse'].current_session, 2005)
415        self.assertEqual(self.student['studycourse'].current_level, 110)
416
417        self.student['studycourse'].current_session = 2004
418        self.student['studycourse'].current_level = 100
419        self.student['studycourse'].current_verdict = 'D'
420        utils.setReturningData(self.student)
421        self.assertEqual(self.student['studycourse'].current_session, 2005)
422        self.assertEqual(self.student['studycourse'].current_level, 100)
423        return
424
425    def test_set_payment_details(self):
426        self.app['configuration']['2004'].gown_fee = 150.0
427        self.app['configuration']['2004'].transfer_fee = 90.0
428        self.app['configuration']['2004'].booking_fee = 150.0
429        self.app['configuration']['2004'].maint_fee = 180.0
430
431        configuration = createObject('waeup.SessionConfiguration')
432        configuration.academic_session = 2000
433        self.app['configuration'].addSessionConfiguration(configuration)
434        configuration2 = createObject('waeup.SessionConfiguration')
435        configuration2.academic_session = 2002
436        self.app['configuration'].addSessionConfiguration(configuration2)
437        configuration3 = createObject('waeup.SessionConfiguration')
438        configuration3.academic_session = 2003
439        self.app['configuration'].addSessionConfiguration(configuration3)
440        configuration4 = createObject('waeup.SessionConfiguration')
441        configuration4.academic_session = 2005
442        self.app['configuration'].addSessionConfiguration(configuration4)
443        utils = getUtility(IStudentsUtils)
444        self.student['studycourse'].entry_session = 2002
445        self.student.nationality = u'NG'
446
447        error, payment = utils.setPaymentDetails('schoolfee',
448            self.student, None, None)
449        self.assertEqual(payment, None)
450        # Student is in state 'created' and can thus not pay.
451        self.assertTrue(u'Amount could not be determined.' in error)
452
453        # Previous session must be valid.
454        error, payment = utils.setPaymentDetails('schoolfee',
455            self.student, 2000, 300)
456        self.assertEqual(payment, None)
457        self.assertTrue(u'The previous session must not fall below' in error)
458        error, payment = utils.setPaymentDetails('schoolfee',
459            self.student, 2005, 300)
460        self.assertEqual(payment, None)
461        self.assertTrue(u'This is not a previous session' in error)
462
463        # Previous session schoolfee payment; fresh and returning
464        # are distinguished by their entry_level
465        error, payment = utils.setPaymentDetails('schoolfee',
466            self.student, 2002, 300)
467        self.assertEqual(payment.amount_auth, 40000.0)
468        self.assertEqual(payment.p_session, 2002)
469        self.assertEqual(payment.p_level, 300)
470        self.assertFalse(payment.p_current)
471        error, payment = utils.setPaymentDetails('schoolfee',
472            self.student, 2003, 300)
473        self.assertEqual(payment.amount_auth, 20000.0)
474        self.assertEqual(payment.p_session, 2003)
475        self.assertEqual(payment.p_level, 300)
476        self.assertFalse(payment.p_current)
477
478        # Current schoolfee payment; fresh and returning
479        # are distinguished by their state
480        IWorkflowState(self.student).setState('cleared')
481        error, payment = utils.setPaymentDetails('schoolfee',
482            self.student, None, None)
483        self.assertEqual(payment.p_level, 100)
484        self.assertEqual(payment.p_session, 2004)
485        self.assertEqual(payment.amount_auth, 40000.0)
486        self.assertEqual(payment.p_item, u'CERT1')
487        self.assertEqual(error, None)
488        self.assertTrue(payment.p_current)
489
490        # Add penalty fee ...
491        # ... for cleared
492        self.app['configuration']['2004'].penalty_ug = 99.0
493        # ... for returning
494        self.app['configuration']['2005'].penalty_ug = 88.0
495        error, payment = utils.setPaymentDetails('schoolfee',
496            self.student, None, None)
497        self.assertEqual(payment.amount_auth, 40099.0)
498
499        IWorkflowState(self.student).setState('returning')
500
501
502        #error, payment = utils.setPaymentDetails('schoolfee',
503        #    self.student, None, None)
504        #self.assertTrue(
505        #    u'You have not yet paid your current/active session.' in error)
506        ## Ok, that means we have to add paid payment ticket first.
507        #payment = createObject('waeup.StudentOnlinePayment')
508        #payment.p_category = u'schoolfee'
509        #payment.p_session = self.student.current_session
510        #payment.p_item = u'My Certificate'
511        #payment.p_id = u'anyid'
512        #payment.p_state = u'paid'
513        #self.student['payments']['anykey'] = payment
514
515
516        error, payment = utils.setPaymentDetails('schoolfee',
517            self.student, None, None)
518        self.assertEqual(payment.p_level, 200)
519        self.assertEqual(payment.p_session, 2005)
520        self.assertEqual(payment.amount_auth, 20088.0)
521        self.assertEqual(payment.p_item, u'CERT1')
522        self.assertEqual(error, None)
523
524        # Staff members pay less.
525        self.student.is_staff = True
526        error, payment = utils.setPaymentDetails('schoolfee',
527            self.student, None, None)
528        self.assertEqual(payment.p_level, 200)
529        self.assertEqual(payment.p_session, 2005)
530        self.assertEqual(payment.amount_auth, 10088.0)
531        self.assertEqual(payment.p_item, u'CERT1')
532        self.assertEqual(error, None)
533
534        # Foreigners pay more.
535        IWorkflowState(self.student).setState('cleared')
536        self.student.is_staff = False
537        self.student.nationality = u'DE'
538        self.certificate.school_fee_3 = 60000.0
539        error, payment = utils.setPaymentDetails(
540            'schoolfee', self.student, None, None)
541        self.assertEqual(payment.p_level, 100)
542        self.assertEqual(payment.p_session, 2004)
543        self.assertEqual(payment.amount_auth, 60099.0)
544        self.assertEqual(payment.p_item, u'CERT1')
545        self.assertEqual(error, None)
546        IWorkflowState(self.student).setState('returning')
547        self.student.is_staff = False
548        self.certificate.school_fee_4 = 20000.0
549        error, payment = utils.setPaymentDetails(
550            'schoolfee', self.student, None, None)
551        self.assertEqual(payment.p_level, 200)
552        self.assertEqual(payment.p_session, 2005)
553        self.assertEqual(payment.amount_auth, 20088.0)
554        self.assertEqual(payment.p_item, u'CERT1')
555        self.assertEqual(error, None)
556
557        # In Uniben students can pay school fee in all states no matter
558        # if they are ug or pg students.
559        IWorkflowState(self.student).setState('school fee paid')
560        self.student.is_staff = False
561        self.student.nationality = u'NG'
562        self.certificate.school_fee_2 = 10000.0
563        error, payment = utils.setPaymentDetails(
564            'schoolfee', self.student, None, None)
565        self.assertEqual(payment.p_level, None)
566        self.assertEqual(payment.p_session, 2005)
567        self.assertEqual(payment.amount_auth, 10088.0)
568        self.assertEqual(payment.p_item, u'CERT1')
569        self.assertEqual(error, None)
570        IWorkflowState(self.student).setState('courses registered')
571        self.certificate.study_mode = 'special_pg_pt'
572        error, payment = utils.setPaymentDetails(
573            'schoolfee', self.student, None, None)
574        self.assertEqual(payment.p_level, None)
575        self.assertEqual(payment.p_session, 2005)
576        self.assertEqual(payment.amount_auth, 10000.0)
577        self.assertEqual(payment.p_item, u'CERT1')
578        self.assertEqual(error, None)
579        IWorkflowState(self.student).setState('courses validated')
580        error, payment = utils.setPaymentDetails(
581            'schoolfee', self.student, None, None)
582        self.assertEqual(payment.p_level, None)
583        self.assertEqual(payment.p_session, 2005)
584        self.assertEqual(payment.amount_auth, 10000.0)
585        self.assertEqual(payment.p_item, u'CERT1')
586        self.assertEqual(error, None)
587
588        error, payment = utils.setPaymentDetails('clearance',
589            self.student, None, None)
590        self.assertEqual(payment.p_level, 100)
591        self.assertEqual(payment.p_session, 2004)
592        self.assertEqual(payment.amount_auth, 45000.0)
593        self.assertEqual(payment.p_item, u'CERT1')
594        self.assertEqual(error, None)
595
596        error, payment = utils.setPaymentDetails('gown',
597            self.student, None, None)
598        self.assertEqual(payment.p_level, 100)
599        self.assertEqual(payment.p_session, 2004)
600        self.assertEqual(payment.amount_auth, 150.0)
601        self.assertEqual(payment.p_item, u'')
602        self.assertEqual(error, None)
603
604        #error, payment = utils.setPaymentDetails('hostel_maintenance',
605        #    self.student, None, None)
606        #self.assertEqual(payment.p_level, 100)
607        #self.assertEqual(payment.p_session, 2004)
608        #self.assertEqual(payment.amount_auth, 180.0)
609        #self.assertEqual(payment.p_item, u'')
610        #self.assertEqual(error, None)
611
612        #error, payment = utils.setPaymentDetails('bed_allocation',
613        #    self.student, None, None)
614        #self.assertEqual(payment.p_level, 100)
615        #self.assertEqual(payment.p_session, 2004)
616        #self.assertEqual(payment.amount_auth, 150.0)
617        #self.assertEqual(payment.p_item, u'')
618        #self.assertEqual(error, None)
619
620        error, payment = utils.setPaymentDetails('hostel_application',
621            self.student, None, None)
622        self.assertEqual(payment.p_level, 100)
623        self.assertEqual(payment.p_session, 2004)
624        self.assertEqual(payment.amount_auth, 1000.0)
625        self.assertEqual(payment.p_item, u'')
626        self.assertEqual(error, None)
627
628        payment.approve()
629        self.student['payments'][payment.p_id] = payment
630
631        error, payment = utils.setPaymentDetails('tempmaint_1',
632            self.student, None, None)
633        self.assertEqual(payment.p_level, 100)
634        self.assertEqual(payment.p_session, 2004)
635        self.assertEqual(payment.amount_auth, 8150.0)
636        self.assertEqual(payment.p_item, u'Hall 1-4 M/F Ekehuan')
637        self.assertEqual(error, None)
638
639        error, payment = utils.setPaymentDetails('tempmaint_2',
640            self.student, None, None)
641        self.assertEqual(payment.p_level, 100)
642        self.assertEqual(payment.p_session, 2004)
643        self.assertEqual(payment.amount_auth, 12650.0)
644        self.assertEqual(payment.p_item, u'Hall 5 M/F')
645        self.assertEqual(error, None)
646
647        error, payment = utils.setPaymentDetails('tempmaint_3',
648            self.student, None, None)
649        self.assertEqual(payment.p_level, 100)
650        self.assertEqual(payment.p_session, 2004)
651        self.assertEqual(payment.amount_auth, 9650.0)
652        self.assertEqual(payment.p_item, u'Clinical Hostel')
653        self.assertEqual(error, None)
654
655        error, payment = utils.setPaymentDetails('transfer',
656            self.student, None, None)
657        self.assertEqual(payment.p_level, 100)
658        self.assertEqual(payment.p_session, 2004)
659        self.assertEqual(payment.amount_auth, 90.0)
660        self.assertEqual(payment.p_item, u'')
661        self.assertEqual(error, None)
662        return
663
664    def test_edit_level_by_co(self):
665        # Create clearance officer
666        self.app['users'].addUser('mrclear', 'mrclearsecret')
667        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
668        self.app['users']['mrclear'].title = 'Carlo Pitter'
669        # Assign local ClearanceOfficer role
670        department = self.app['faculties']['fac1']['dep1']
671        prmlocal = IPrincipalRoleManager(department)
672        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
673        notify(LocalRoleSetEvent(
674            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
675        IWorkflowState(self.student).setState('clearance started')
676        # Login as clearance officer
677        self.browser.open(self.login_path)
678        self.browser.getControl(name="form.login").value = 'mrclear'
679        self.browser.getControl(name="form.password").value = 'mrclearsecret'
680        self.browser.getControl("Login").click()
681        self.assertMatches('...You logged in...', self.browser.contents)
682        # Only in state clearance requested the CO does see the
683        # 'Edit level' button ...
684        self.browser.open(self.studycourse_path)
685        self.assertFalse('Edit level' in self.browser.contents)
686        # ... and can open the edit_level view
687        self.browser.open(self.studycourse_path + '/edit_level')
688        self.assertMatches('...is locked...', self.browser.contents)
689        self.assertEqual(self.browser.url, self.studycourse_path)
690        IWorkflowInfo(self.student).fireTransition('request_clearance')
691        self.browser.open(self.studycourse_path)
692        self.assertTrue('Edit level' in self.browser.contents)
693        self.browser.getLink("Edit level").click()
694        self.browser.getControl(name="form.current_level").value = ['200']
695        self.browser.getControl("Save").click()
696        self.assertMatches('...has been saved...', self.browser.contents)
697        self.assertEqual(self.student.current_level, 200)
698
699    def test_postgraduate_student_access(self):
700        self.certificate.study_mode = 'special_pg_pt'
701        self.certificate.start_level = 700
702        self.certificate.end_level = 800
703        self.student['studycourse'].current_level = 700
704        IWorkflowState(self.student).setState('school fee paid')
705        self.browser.open(self.login_path)
706        self.browser.getControl(name="form.login").value = self.student_id
707        self.browser.getControl(name="form.password").value = 'spwd'
708        self.browser.getControl("Login").click()
709        self.assertTrue(
710            'You logged in.' in self.browser.contents)
711        # Now students can add the current study level
712        self.browser.getLink("Study Course").click()
713        self.browser.getLink("Add course list").click()
714        self.assertMatches('...Add current level 700...',
715                           self.browser.contents)
716        self.browser.getControl("Create course list now").click()
717        # A level with no course ticket was created
718        self.assertEqual(self.student['studycourse']['700'].number_of_tickets, 0)
719        self.browser.getLink("700").click()
720        self.browser.getLink("Edit course list").click()
721        self.browser.getLink("here").click()
722        self.browser.getControl(name="form.course").value = ['COURSE1']
723        # Non-final year students can't add ticket with 51 credits
724        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
725        self.browser.getControl("Add course ticket").click()
726        self.assertMatches('...Total credits exceed 50...',
727                           self.browser.contents)
728        # Final year students can't add ticket with 52 credits ...
729        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 52
730        self.student['studycourse'].certificate.end_level = 700
731        self.browser.getControl("Add course ticket").click()
732        self.assertMatches('...Total credits exceed 51...',
733                           self.browser.contents)
734        # ... but with 51 credits
735        self.app['faculties']['fac1']['dep1'].courses['COURSE1'].credits = 51
736        self.browser.getControl("Add course ticket").click()
737        self.assertMatches('...Successfully added COURSE1...',
738                           self.browser.contents)
739        # Non-final year special postgraduate students can't register
740        # course lists if their total credits are 51 and thus exceed 50 ...
741        self.student['studycourse'].certificate.end_level = 800
742        self.browser.getControl("Register course list").click()
743        self.assertMatches('...Maximum credits of 50 exceeded...',
744            self.browser.contents)
745        # ... but final year students can
746        self.student['studycourse'].certificate.end_level = 700
747        self.browser.getControl("Register course list").click()
748        self.assertMatches('...Course list has been registered...',
749            self.browser.contents)
750        self.assertEqual(self.student.state, 'courses registered')
751        return
752
753    def test_login(self):
754        # If suspended_comment is set this message will be flashed instead
755        self.student.suspended_comment = u'Aetsch baetsch!'
756        self.student.suspended = True
757        self.browser.open(self.login_path)
758        self.browser.getControl(name="form.login").value = self.student_id
759        self.browser.getControl(name="form.password").value = 'spwd'
760        self.browser.getControl("Login").click()
761        # Uniben does not display suspended_comment
762        self.assertMatches(
763            '...<div class="alert alert-warning">Your account has been deactivated.</div>...',
764            self.browser.contents)
765        self.student.suspended = False
766
767    def test_activate_deactivate_buttons(self):
768        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
769        self.browser.open(self.student_path)
770        self.browser.getLink("Deactivate").click()
771        self.assertTrue(
772            'Student account has been deactivated.' in self.browser.contents)
773        self.assertTrue(
774            'Base Data (account deactivated)' in self.browser.contents)
775        self.assertTrue(self.student.suspended)
776        self.browser.getLink("Activate").click()
777        self.assertTrue(
778            'Student account has been activated.' in self.browser.contents)
779        self.assertFalse(
780            'Base Data (account deactivated)' in self.browser.contents)
781        self.assertFalse(self.student.suspended)
782        # History messages have been added ...
783        self.browser.getLink("History").click()
784        # User is undisclosed
785        self.assertTrue(
786            'Student account deactivated<br />' in self.browser.contents)
787        self.assertTrue(
788            'Student account activated<br />' in self.browser.contents)
789        # ... and actions have been logged.
790        logfile = os.path.join(
791            self.app['datacenter'].storage, 'logs', 'students.log')
792        logcontent = open(logfile).read()
793        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentDeactivatePage - '
794                        'B1000000 - account deactivated' in logcontent)
795        self.assertTrue('zope.mgr - waeup.uniben.students.browser.CustomStudentActivatePage - '
796                        'B1000000 - account activated' in logcontent)
797
798    def test_manage_upload_fpm_file(self):
799        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
800        self.browser.open(self.manage_clearance_path)
801        image = open(SAMPLE_FPM, 'rb')
802        ctrl = self.browser.getControl(name='leftthumbprintupload')
803        file_ctrl = ctrl.mech_control
804        file_ctrl.add_file(image, filename='thumbprint.fpm')
805        self.browser.getControl(
806            name='upload_leftthumbprintupload').click()
807        self.assertTrue(
808            'File finger1.fpm uploaded.' in self.browser.contents)
809        self.assertTrue(
810            'http://localhost/app/students/B1000000/finger1.fpm'
811            in self.browser.contents)
812        self.browser.getControl(
813            name='delete_leftthumbprintupload').click()
814        self.assertTrue(
815            'finger1.fpm deleted'
816            in self.browser.contents)
817
818    def test_handle_clearance_by_co(self):
819        # Create clearance officer
820        self.app['users'].addUser('mrclear', 'mrclearsecret')
821        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
822        self.app['users']['mrclear'].title = 'Carlo Pitter'
823        department = self.app['faculties']['fac1']['dep1']
824        prmlocal = IPrincipalRoleManager(department)
825        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
826        notify(LocalRoleSetEvent(
827            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
828        IWorkflowState(self.student).setState('clearance requested')
829        # Login as clearance officer
830        self.browser.open(self.login_path)
831        self.browser.getControl(name="form.login").value = 'mrclear'
832        self.browser.getControl(name="form.password").value = 'mrclearsecret'
833        self.browser.getControl("Login").click()
834        self.assertMatches('...You logged in...', self.browser.contents)
835        # CO can view the student ...
836        self.browser.open(self.clearance_path)
837        self.assertEqual(self.browser.headers['Status'], '200 Ok')
838        self.assertEqual(self.browser.url, self.clearance_path)
839        # Clearance is disabled for this session for ug students ...
840        self.browser.open(self.clearance_path)
841        self.assertFalse('Clear student' in self.browser.contents)
842        self.browser.open(self.student_path + '/clear')
843        self.assertTrue('Clearance is disabled for this session'
844            in self.browser.contents)
845        # ... but not for
846        self.certificate.study_mode = 'pg_ft'
847        self.browser.open(self.clearance_path)
848        self.assertTrue('Clear student' in self.browser.contents)
849        self.browser.open(self.student_path + '/clear')
850        self.assertTrue('Student has been cleared' in self.browser.contents)
851
852    def test_transcripts(self):
853        studylevel = createObject(u'waeup.StudentStudyLevel')
854        studylevel.level = 100
855        studylevel.level_session = 2005
856        self.student['studycourse'].entry_mode = 'ug_ft'
857        self.student['studycourse'].addStudentStudyLevel(
858            self.certificate, studylevel)
859        studylevel2 = createObject(u'waeup.StudentStudyLevel')
860        studylevel2.level = 110
861        studylevel2.level_session = 2006
862        self.student['studycourse'].addStudentStudyLevel(
863            self.certificate, studylevel2)
864        # Add second course (COURSE has been added automatically)
865        courseticket = createObject('waeup.CourseTicket')
866        courseticket.code = 'ANYCODE'
867        courseticket.title = u'Any TITLE'
868        courseticket.credits = 13
869        courseticket.score = 66
870        courseticket.semester = 1
871        courseticket.dcode = u'ANYDCODE'
872        courseticket.fcode = u'ANYFCODE'
873        self.student['studycourse']['110']['COURSE2'] = courseticket
874        self.student['studycourse']['100']['COURSE1'].score = 55
875        self.assertEqual(self.student['studycourse']['100'].gpa_params_rectified[0], 3.0)
876        self.assertEqual(self.student['studycourse']['110'].gpa_params_rectified[0], 4.0)
877        # Get transcript data
878        td = self.student['studycourse'].getTranscriptData()
879        self.assertEqual(td[0][0]['level_key'], '100')
880        self.assertEqual(td[0][0]['sgpa'], 3.0)
881        self.assertEqual(td[0][0]['level'].level, 100)
882        self.assertEqual(td[0][0]['level'].level_session, 2005)
883        self.assertEqual(td[0][0]['tickets_1'][0].code, 'COURSE1')
884        self.assertEqual(td[0][1]['level_key'], '110')
885        self.assertEqual(td[0][1]['sgpa'], 4.0)
886        self.assertEqual(td[0][1]['level'].level, 110)
887        self.assertEqual(td[0][1]['level'].level_session, 2006)
888        self.assertEqual(td[0][1]['tickets_1'][0].code, 'ANYCODE')
889        self.assertEqual(td[1], 3.57)
890        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
891        self.browser.open(self.student_path + '/studycourse/transcript')
892        self.assertEqual(self.browser.headers['Status'], '200 Ok')
893        self.assertTrue('Transcript' in self.browser.contents)
894        # Officers can open the pdf transcript
895        self.browser.open(self.student_path + '/studycourse/transcript.pdf')
896        self.assertEqual(self.browser.headers['Status'], '200 Ok')
897        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
898        path = os.path.join(samples_dir(), 'transcript.pdf')
899        open(path, 'wb').write(self.browser.contents)
900        print "Sample PDF transcript.pdf written to %s" % path
Note: See TracBrowser for help on using the repository browser.