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

Last change on this file since 9346 was 9346, checked in by Henrik Bettermann, 12 years ago

New clearance fees.

  • Property svn:keywords set to Id
File size: 24.5 KB
Line 
1## $Id: test_browser.py 9346 2012-10-18 04:49:58Z 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.testing import FunctionalTestCase
32from waeup.kofa.interfaces import (
33    IExtFileStore, IFileStoreNameChooser)
34from waeup.kofa.students.interfaces import IStudentsUtils
35from waeup.uniben.testing import FunctionalLayer
36
37
38class StudentProcessorTest(FunctionalTestCase):
39    """Perform some batching tests.
40    """
41
42    layer = FunctionalLayer
43
44    def setUp(self):
45        super(StudentProcessorTest, self).setUp()
46        # Setup a sample site for each test
47        app = University()
48        self.dc_root = tempfile.mkdtemp()
49        app['datacenter'].setStoragePath(self.dc_root)
50
51        # Prepopulate the ZODB...
52        self.getRootFolder()['app'] = app
53        # we add the site immediately after creation to the
54        # ZODB. Catalogs and other local utilities are not setup
55        # before that step.
56        self.app = self.getRootFolder()['app']
57        # Set site here. Some of the following setup code might need
58        # to access grok.getSite() and should get our new app then
59        setSite(app)
60
61
62    def tearDown(self):
63        super(StudentProcessorTest, self).tearDown()
64        shutil.rmtree(self.workdir)
65        shutil.rmtree(self.dc_root)
66        clearSite()
67        return
68
69class StudentUITests(StudentsFullSetup):
70    """Tests for customized student class views and pages
71    """
72
73    layer = FunctionalLayer
74
75    def test_next_session_allowed(self):
76        # Let's see if next_session_allowed works as expected
77        # A, ug_ft, 100
78        IWorkflowState(self.student).setState('returning')
79        self.assertTrue(self.student['studycourse'].next_session_allowed)
80        # Uniben special PG programmes have the same workflow
81        # as UG students
82        self.certificate.study_mode = 'special_pg_pt'
83        self.assertTrue(self.student['studycourse'].next_session_allowed)
84        IWorkflowState(self.student).setState('school fee paid')
85        self.assertFalse(self.student['studycourse'].next_session_allowed)
86        # Now we convert the certificate into a 'regular
87        # postgraduate certificate ...
88        self.certificate.study_mode = 'pg_ft'
89        # ... and voila next session registration is allowed
90        self.assertTrue(self.student['studycourse'].next_session_allowed)
91
92    def test_manage_access(self):
93        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
94        # The student created in the base package is a ug student
95        self.browser.open(self.manage_clearance_path)
96        self.assertMatches('...First Sitting Record...',
97                           self.browser.contents)
98        # There is no pg field in the clearance form
99        self.assertFalse('Second Higher Education Record'
100            in self.browser.contents)
101        # Now we change the study mode ...
102        self.certificate.study_mode = 'pg_ft'
103        self.browser.open(self.clearance_path)
104        # ... and additional pg clearance fields appear
105        self.assertMatches('...Second Higher Education Record...',
106                           self.browser.contents)
107        # But also fields from the ug form are displayed
108        self.assertMatches('...First Sitting Record...',
109                           self.browser.contents)
110        # The same holds for Uniben's special pg students
111        self.certificate.study_mode = 'special_pg_ft'
112        self.browser.open(self.clearance_path)
113        self.assertMatches('...Second Higher Education Record...',
114                           self.browser.contents)
115        self.assertMatches('...First Sitting Record...',
116                           self.browser.contents)
117
118    def test_manage_payments(self):
119        # Add missing configuration data
120        self.app['configuration']['2004'].gown_fee = 150.0
121        self.app['configuration']['2004'].transfer_fee = 90.0
122        #self.app['configuration']['2004'].clearance_fee = 120.0
123        self.app['configuration']['2004'].booking_fee = 150.0
124        self.app['configuration']['2004'].maint_fee = 180.0
125
126        # Managers can add online payment tickets
127        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
128        self.browser.open(self.payments_path)
129        self.browser.getControl("Add online payment ticket").click()
130        self.browser.getControl("Create ticket").click()
131        self.assertMatches('...Amount could not be determined...',
132                           self.browser.contents)
133        IWorkflowState(self.student).setState('cleared')
134        self.student.nationality = u'NG'
135        self.browser.open(self.payments_path + '/addop')
136        self.browser.getControl("Create ticket").click()
137        self.assertMatches('...ticket created...',
138                           self.browser.contents)
139        ctrl = self.browser.getControl(name='val_id')
140        value = ctrl.options[0]
141        self.browser.getLink(value).click()
142        self.assertMatches('...Amount Authorized...',
143                           self.browser.contents)
144        # Managers can open payment slip
145        self.browser.getLink("Download payment slip").click()
146        self.assertEqual(self.browser.headers['Status'], '200 Ok')
147        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
148        # Set ticket paid
149        ticket = self.student['payments'].items()[0][1]
150        ticket.p_state = 'paid'
151        self.browser.open(self.payments_path + '/addop')
152        self.browser.getControl("Create ticket").click()
153        self.assertMatches('...This type of payment has already been made...',
154                           self.browser.contents)
155        # Remove all payments so that we can add a school fee payment again
156        keys = [i for i in self.student['payments'].keys()]
157        for payment in keys:
158            del self.student['payments'][payment]
159        self.browser.open(self.payments_path + '/addop')
160        self.browser.getControl("Create ticket").click()
161        self.assertMatches('...ticket created...',
162                           self.browser.contents)
163        self.browser.open(self.payments_path + '/addop')
164        self.browser.getControl(name="form.p_category").value = ['gown']
165        self.browser.getControl("Create ticket").click()
166        self.assertMatches('...ticket created...',
167                           self.browser.contents)
168        self.browser.open(self.payments_path + '/addop')
169        self.browser.getControl(name="form.p_category").value = ['transfer']
170        self.browser.getControl("Create ticket").click()
171        self.assertMatches('...ticket created...',
172                           self.browser.contents)
173        self.browser.open(self.payments_path + '/addop')
174        self.browser.getControl(
175            name="form.p_category").value = ['bed_allocation']
176        self.browser.getControl("Create ticket").click()
177        self.assertMatches('...ticket created...',
178                           self.browser.contents)
179        self.browser.open(self.payments_path + '/addop')
180        self.browser.getControl(
181            name="form.p_category").value = ['hostel_maintenance']
182        self.browser.getControl("Create ticket").click()
183        self.assertMatches('...ticket created...',
184                           self.browser.contents)
185        self.browser.open(self.payments_path + '/addop')
186        self.browser.getControl(name="form.p_category").value = ['clearance']
187        self.browser.getControl("Create ticket").click()
188        self.assertMatches('...ticket created...',
189                           self.browser.contents)
190        self.browser.open(self.payments_path + '/addop')
191        self.browser.getControl(name="form.p_category").value = ['schoolfee']
192        self.browser.getControl("Create ticket").click()
193        self.assertMatches('...ticket created...',
194                           self.browser.contents)
195        # In state returning we can add a new school fee ticket since
196        # p_session and p_level is different
197        IWorkflowState(self.student).setState('returning')
198        self.browser.open(self.payments_path + '/addop')
199        self.browser.getControl(name="form.p_category").value = ['schoolfee']
200        self.browser.getControl("Create ticket").click()
201        self.assertMatches('...Session configuration object is not...',
202                           self.browser.contents)
203        # Uups, we forgot to add a session configuration for next session
204        configuration = createObject('waeup.SessionConfiguration')
205        configuration.academic_session = 2005
206        self.app['configuration'].addSessionConfiguration(configuration)
207        self.browser.open(self.payments_path + '/addop')
208        self.browser.getControl(name="form.p_category").value = ['schoolfee']
209        self.browser.getControl("Create ticket").click()
210        self.assertMatches('...ticket created...',
211                           self.browser.contents)
212        # In state admitted school fee can't be determined
213        IWorkflowState(self.student).setState('admitted')
214        self.browser.open(self.payments_path + '/addop')
215        self.browser.getControl(name="form.p_category").value = ['schoolfee']
216        self.browser.getControl("Create ticket").click()
217        self.assertMatches('...Amount could not be determined...',
218                           self.browser.contents)
219
220        # If the session configuration doesn't exist an error message will
221        # be shown. No other requirement is being checked.
222        del self.app['configuration']['2004']
223        self.browser.open(self.payments_path)
224        self.browser.getControl("Add online payment ticket").click()
225        self.browser.getControl("Create ticket").click()
226        self.assertMatches('...Session configuration object is not...',
227                           self.browser.contents)
228
229    def test_get_returning_data(self):
230        # Student is in level 100, session 2004 with verdict A
231        utils = getUtility(IStudentsUtils)
232        self.assertEqual(utils.getReturningData(self.student),(2005, 200))
233        self.student['studycourse'].current_verdict = 'C'
234        self.assertEqual(utils.getReturningData(self.student),(2005, 110))
235        self.student['studycourse'].current_verdict = 'D'
236        self.assertEqual(utils.getReturningData(self.student),(2005, 100))
237        return
238
239    def test_set_returning_data(self):
240        # Student is in level 100, session 2004 with verdict A
241        utils = getUtility(IStudentsUtils)
242
243        utils.setReturningData(self.student)
244        self.assertEqual(self.student['studycourse'].current_session, 2005)
245        self.assertEqual(self.student['studycourse'].current_level, 200)
246
247        self.student['studycourse'].current_session = 2004
248        self.student['studycourse'].current_level = 100
249        self.student['studycourse'].current_verdict = 'C'
250        utils.setReturningData(self.student)
251        self.assertEqual(self.student['studycourse'].current_session, 2005)
252        self.assertEqual(self.student['studycourse'].current_level, 110)
253
254        self.student['studycourse'].current_session = 2004
255        self.student['studycourse'].current_level = 100
256        self.student['studycourse'].current_verdict = 'D'
257        utils.setReturningData(self.student)
258        self.assertEqual(self.student['studycourse'].current_session, 2005)
259        self.assertEqual(self.student['studycourse'].current_level, 100)
260        return
261
262    def test_set_payment_details(self):
263        self.app['configuration']['2004'].gown_fee = 150.0
264        self.app['configuration']['2004'].transfer_fee = 90.0
265        self.app['configuration']['2004'].booking_fee = 150.0
266        self.app['configuration']['2004'].maint_fee = 180.0
267
268        configuration = createObject('waeup.SessionConfiguration')
269        configuration.academic_session = 2000
270        self.app['configuration'].addSessionConfiguration(configuration)
271        configuration2 = createObject('waeup.SessionConfiguration')
272        configuration2.academic_session = 2002
273        self.app['configuration'].addSessionConfiguration(configuration2)
274        configuration3 = createObject('waeup.SessionConfiguration')
275        configuration3.academic_session = 2003
276        self.app['configuration'].addSessionConfiguration(configuration3)
277
278        utils = getUtility(IStudentsUtils)
279
280        self.student['studycourse'].entry_session = 2002
281        self.student.nationality = u'NG'
282
283        configuration = createObject('waeup.SessionConfiguration')
284        configuration.academic_session = 2005
285        self.app['configuration'].addSessionConfiguration(configuration)
286
287        error, payment = utils.setPaymentDetails('schoolfee',
288            self.student, None, None)
289        self.assertEqual(payment, None)
290        self.assertTrue(u'Amount could not be determined.' in error)
291
292        # Previous session must be valid.
293        error, payment = utils.setPaymentDetails('schoolfee',
294            self.student, 2000, 300)
295        self.assertEqual(payment, None)
296        self.assertTrue(u'The previous session must not fall below' in error)
297        error, payment = utils.setPaymentDetails('schoolfee',
298            self.student, 2004, 300)
299        self.assertEqual(payment, None)
300        self.assertTrue(u'This is not a previous session' in error)
301
302        # Previous session payment; fresh and returning
303        # are distinguished by their entry_level
304        error, payment = utils.setPaymentDetails('schoolfee',
305            self.student, 2002, 300)
306        self.assertEqual(payment.amount_auth, 40000.0)
307        self.assertEqual(payment.p_session, 2002)
308        self.assertEqual(payment.p_level, 300)
309        self.assertFalse(payment.p_current)
310        error, payment = utils.setPaymentDetails('schoolfee',
311            self.student, 2003, 300)
312        self.assertEqual(payment.amount_auth, 20000.0)
313        self.assertEqual(payment.p_session, 2003)
314        self.assertEqual(payment.p_level, 300)
315        self.assertFalse(payment.p_current)
316
317        # Current payment; fresh and returning
318        # are distinguished by their state
319        IWorkflowState(self.student).setState('cleared')
320        error, payment = utils.setPaymentDetails('schoolfee',
321            self.student, None, None)
322        self.assertEqual(payment.p_level, 100)
323        self.assertEqual(payment.p_session, 2004)
324        self.assertEqual(payment.amount_auth, 40000.0)
325        self.assertEqual(payment.p_item, u'CERT1')
326        self.assertEqual(error, None)
327        self.assertTrue(payment.p_current)
328
329        # Add penalty fee ...
330        # ... for cleared
331        self.app['configuration']['2004'].penalty_ug = 99.0
332        # ... for returning
333        self.app['configuration']['2005'].penalty_ug = 88.0
334        error, payment = utils.setPaymentDetails('schoolfee',
335            self.student, None, None)
336        self.assertEqual(payment.amount_auth, 40099.0)
337
338        IWorkflowState(self.student).setState('returning')
339        error, payment = utils.setPaymentDetails('schoolfee',
340            self.student, None, None)
341        self.assertEqual(payment.p_level, 200)
342        self.assertEqual(payment.p_session, 2005)
343        self.assertEqual(payment.amount_auth, 20088.0)
344        self.assertEqual(payment.p_item, u'CERT1')
345        self.assertEqual(error, None)
346        self.student.is_staff = True
347        error, payment = utils.setPaymentDetails('schoolfee',
348            self.student, None, None)
349        self.assertEqual(payment.p_level, 200)
350        self.assertEqual(payment.p_session, 2005)
351        self.assertEqual(payment.amount_auth, 10088.0)
352        self.assertEqual(payment.p_item, u'CERT1')
353        self.assertEqual(error, None)
354
355        IWorkflowState(self.student).setState('cleared')
356        self.student.is_staff = False
357        self.student.nationality = u'DE'
358        self.certificate.school_fee_3 = 60000.0
359        error, payment = utils.setPaymentDetails(
360            'schoolfee', self.student, None, None)
361        self.assertEqual(payment.p_level, 100)
362        self.assertEqual(payment.p_session, 2004)
363        self.assertEqual(payment.amount_auth, 60099.0)
364        self.assertEqual(payment.p_item, u'CERT1')
365        self.assertEqual(error, None)
366
367        IWorkflowState(self.student).setState('returning')
368        self.student.is_staff = False
369        self.student.nationality = u'DE'
370        self.certificate.school_fee_4 = 20000.0
371        error, payment = utils.setPaymentDetails(
372            'schoolfee', self.student, None, None)
373        self.assertEqual(payment.p_level, 200)
374        self.assertEqual(payment.p_session, 2005)
375        self.assertEqual(payment.amount_auth, 20088.0)
376        self.assertEqual(payment.p_item, u'CERT1')
377        self.assertEqual(error, None)
378
379        # In Uniben we have pg and special pg students.
380        # They pay the same but their workflow is different.
381        IWorkflowState(self.student).setState('school fee paid')
382        self.student.is_staff = False
383        self.student.nationality = u'NG'
384        self.certificate.school_fee_2 = 10000.0
385        error, payment = utils.setPaymentDetails(
386            'schoolfee', self.student, None, None)
387        self.assertEqual(payment, None)
388        self.assertTrue('not be determined' in error)
389        self.certificate.study_mode = 'pg_pt'
390        self.assertTrue(self.student.is_postgrad)
391        self.assertFalse(self.student.is_special_postgrad)
392        error, payment = utils.setPaymentDetails(
393            'schoolfee', self.student, None, None)
394        self.assertEqual(payment.p_level, 100)
395        self.assertEqual(payment.p_session, 2005)
396        self.assertEqual(payment.amount_auth, 10000.0)
397        self.assertEqual(payment.p_item, u'CERT1')
398        self.assertEqual(error, None)
399        self.certificate.study_mode = 'special_pg_pt'
400        self.assertTrue(self.student.is_postgrad)
401        self.assertTrue(self.student.is_special_postgrad)
402        error, payment = utils.setPaymentDetails(
403            'schoolfee', self.student, None, None)
404        self.assertTrue('not be determined' in error)
405        IWorkflowState(self.student).setState('returning')
406        error, payment = utils.setPaymentDetails(
407            'schoolfee', self.student, None, None)
408        self.assertEqual(payment.p_level, 200)
409        self.assertEqual(payment.p_session, 2005)
410        self.assertEqual(payment.amount_auth, 10000.0)
411        self.assertEqual(payment.p_item, u'CERT1')
412        self.assertEqual(error, None)
413
414        error, payment = utils.setPaymentDetails('clearance',
415            self.student, None, None)
416        self.assertEqual(payment.p_level, 100)
417        self.assertEqual(payment.p_session, 2004)
418        self.assertEqual(payment.amount_auth, 45000.0)
419        self.assertEqual(payment.p_item, u'CERT1')
420        self.assertEqual(error, None)
421
422        error, payment = utils.setPaymentDetails('gown',
423            self.student, None, None)
424        self.assertEqual(payment.p_level, 100)
425        self.assertEqual(payment.p_session, 2004)
426        self.assertEqual(payment.amount_auth, 150.0)
427        self.assertEqual(payment.p_item, u'')
428        self.assertEqual(error, None)
429
430        error, payment = utils.setPaymentDetails('hostel_maintenance',
431            self.student, None, None)
432        self.assertEqual(payment.p_level, 100)
433        self.assertEqual(payment.p_session, 2004)
434        self.assertEqual(payment.amount_auth, 180.0)
435        self.assertEqual(payment.p_item, u'')
436        self.assertEqual(error, None)
437
438        error, payment = utils.setPaymentDetails('bed_allocation',
439            self.student, None, None)
440        self.assertEqual(payment.p_level, 100)
441        self.assertEqual(payment.p_session, 2004)
442        self.assertEqual(payment.amount_auth, 150.0)
443        self.assertEqual(payment.p_item, u'')
444        self.assertEqual(error, None)
445
446        error, payment = utils.setPaymentDetails('transfer',
447            self.student, None, None)
448        self.assertEqual(payment.p_level, 100)
449        self.assertEqual(payment.p_session, 2004)
450        self.assertEqual(payment.amount_auth, 90.0)
451        self.assertEqual(payment.p_item, u'')
452        self.assertEqual(error, None)
453        return
454
455    def test_edit_level_by_co(self):
456        # Create clearance officer
457        self.app['users'].addUser('mrclear', 'mrclearsecret')
458        self.app['users']['mrclear'].email = 'mrclear@foo.ng'
459        self.app['users']['mrclear'].title = 'Carlo Pitter'
460        # Assign local ClearanceOfficer role
461        department = self.app['faculties']['fac1']['dep1']
462        prmlocal = IPrincipalRoleManager(department)
463        prmlocal.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'mrclear')
464        notify(LocalRoleSetEvent(
465            department, 'waeup.local.ClearanceOfficer', 'mrclear', granted=True))
466        IWorkflowState(self.student).setState('clearance started')
467        # Login as clearance officer
468        self.browser.open(self.login_path)
469        self.browser.getControl(name="form.login").value = 'mrclear'
470        self.browser.getControl(name="form.password").value = 'mrclearsecret'
471        self.browser.getControl("Login").click()
472        self.assertMatches('...You logged in...', self.browser.contents)
473        # Only in state clearance requested the CO does see the
474        # 'Edit level' button ...
475        self.browser.open(self.studycourse_path)
476        self.assertFalse('Edit level' in self.browser.contents)
477        # ... and can open the edit_level view
478        self.browser.open(self.studycourse_path + '/edit_level')
479        self.assertMatches('...is locked...', self.browser.contents)
480        self.assertEqual(self.browser.url, self.studycourse_path)
481        IWorkflowInfo(self.student).fireTransition('request_clearance')
482        self.browser.open(self.studycourse_path)
483        self.assertTrue('Edit level' in self.browser.contents)
484        self.browser.getLink("Edit level").click()
485        self.browser.getControl(name="form.current_level").value = ['200']
486        self.browser.getControl("Save").click()
487        self.assertMatches('...has been saved...', self.browser.contents)
488        self.assertEqual(self.student.current_level, 200)
489
490    def test_postgraduate_student_access(self):
491        self.certificate.study_mode = 'special_pg_pt'
492        self.certificate.start_level = 700
493        self.certificate.end_level = 800
494        self.student['studycourse'].current_level = 700
495        IWorkflowState(self.student).setState('school fee paid')
496        self.browser.open(self.login_path)
497        self.browser.getControl(name="form.login").value = self.student_id
498        self.browser.getControl(name="form.password").value = 'spwd'
499        self.browser.getControl("Login").click()
500        self.assertTrue(
501            'You logged in.' in self.browser.contents)
502        # Now students can add the current study level
503        self.browser.getLink("Study Course").click()
504        self.browser.getLink("Add course list").click()
505        self.assertMatches('...Add current level 700...',
506                           self.browser.contents)
507        self.browser.getControl("Create course list now").click()
508        # A level with one course ticket was created
509        self.assertEqual(self.student['studycourse']['700'].number_of_tickets, 0)
510        self.browser.getLink("700").click()
511        self.browser.getLink("Edit course list").click()
512        self.browser.getControl("Add course ticket").click()
513        self.browser.getControl(name="form.course").value = ['COURSE1']
514        self.browser.getControl("Add course ticket").click()
515        self.assertMatches('...Successfully added COURSE1...',
516                           self.browser.contents)
517        # Special postgraduate students can register course lists
518        self.browser.getControl("Register course list").click()
519        self.assertMatches('...Course list has been registered...',
520            self.browser.contents)
521        self.assertEqual(self.student.state, 'courses registered')
522        return
Note: See TracBrowser for help on using the repository browser.