source: main/waeup.fceokene/trunk/src/waeup/fceokene/students/tests/test_browser.py

Last change on this file was 17734, checked in by Henrik Bettermann, 7 months ago

School fee payments are becoming even more complex.

  • Property svn:keywords set to Id
File size: 23.8 KB
Line 
1## $Id: test_browser.py 17734 2024-04-04 12:19:05Z 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.component.hooks import setSite, clearSite
24from zope.component import getUtility, createObject
25from zope.interface import verify
26from waeup.kofa.app import University
27from waeup.kofa.students.tests.test_browser import (
28    StudentsFullSetup, SAMPLE_IMAGE)
29from waeup.kofa.students.accommodation import BedTicket
30from waeup.kofa.testing import FunctionalTestCase
31from waeup.kofa.browser.tests.test_pdf import samples_dir
32from waeup.kofa.interfaces import (
33    IExtFileStore, IFileStoreNameChooser)
34from waeup.kofa.students.interfaces import IStudentsUtils
35from waeup.fceokene.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 setUp(self):
76        super(StudentUITests, self).setUp()
77
78        bedticket = BedTicket()
79        bedticket.booking_session = 2004
80        bedticket.bed_type = u'any bed type'
81        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
82        bedticket.bed_coordinates = u'My bed coordinates'
83        self.student['accommodation'].addBedTicket(bedticket)
84
85    def test_manage_payments(self):
86        # Add missing configuration data
87        self.app['configuration']['2004'].clearance_fee = 120.0
88        self.app['configuration']['2004'].booking_fee = 150.0
89        self.app['configuration']['2004'].maint_fee = 180.0
90
91        # Managers can add online payment tickets
92        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
93        self.browser.open(self.payments_path)
94        self.browser.getLink("Add current session payment ticket").click()
95        self.browser.getControl(name="form.p_category").value = ['schoolfee']
96        self.browser.getControl("Create ticket").click()
97        self.assertMatches('...Wrong state...',
98                           self.browser.contents)
99        IWorkflowState(self.student).setState('cleared')
100        self.browser.open(self.payments_path + '/addop')
101        self.browser.getControl(name="form.p_category").value = ['schoolfee']
102        self.browser.getControl("Create ticket").click()
103        self.assertMatches('...ticket created...',
104                           self.browser.contents)
105        self.browser.open(self.payments_path)
106        ctrl = self.browser.getControl(name='val_id')
107        value = ctrl.options[0]
108        self.browser.getLink(value).click()
109        self.assertMatches('...Amount Authorized...',
110                           self.browser.contents)
111        # Managers can open payment slip because we did not proceed to
112        # any payment gateway
113        self.assertFalse('Download payment slip' in self.browser.contents)
114        # Set ticket paid
115        ticket = self.student['payments'].items()[0][1]
116        ticket.p_state = 'paid'
117        self.browser.open(self.payments_path + '/addop')
118        self.browser.getControl(name="form.p_category").value = ['schoolfee']
119        self.browser.getControl("Create ticket").click()
120        self.assertMatches('...This type of payment has already been made...',
121                           self.browser.contents)
122        # Remove all payments so that we can add a school fee payment again
123        keys = [i for i in self.student['payments'].keys()]
124        for payment in keys:
125            del self.student['payments'][payment]
126        self.browser.open(self.payments_path + '/addop')
127        self.browser.getControl(name="form.p_category").value = ['schoolfee']
128        self.browser.getControl("Create ticket").click()
129        self.assertMatches('...ticket created...',
130                           self.browser.contents)
131        #self.certificate.study_mode = 'nce_sw'
132        #self.browser.open(self.payments_path + '/addop')
133        #self.browser.getControl(name="form.p_category").value = ['third_semester']
134        #self.browser.getControl("Create ticket").click()
135        #self.assertMatches('...could not be determined...',
136        #                   self.browser.contents)
137        #self.certificate.study_mode = 'nce_ft'
138        #self.browser.open(self.payments_path + '/addop')
139        #self.browser.getControl(name="form.p_category").value = ['third_semester']
140        #self.student['studycourse'].current_level = 300
141        #self.browser.getControl("Create ticket").click()
142        #self.assertMatches('...Amount could not be determined...', self.browser.contents)
143        self.browser.open(self.payments_path + '/addop')
144        self.browser.getControl(
145            name="form.p_category").value = ['bed_allocation']
146        self.browser.getControl("Create ticket").click()
147        self.assertMatches('...ticket created...',
148                           self.browser.contents)
149        self.browser.open(self.payments_path + '/addop')
150        self.browser.getControl(
151            name="form.p_category").value = ['hostel_maintenance']
152        self.browser.getControl("Create ticket").click()
153        self.assertMatches('...ticket created...',
154                           self.browser.contents)
155        self.browser.open(self.payments_path + '/addop')
156        self.browser.getControl(name="form.p_category").value = ['clearance']
157        self.browser.getControl("Create ticket").click()
158        self.assertMatches('...ticket created...',
159                           self.browser.contents)
160        self.certificate.study_mode = 'pd_ft'
161        self.browser.open(self.payments_path + '/addop')
162        self.browser.getControl(name="form.p_category").value = ['schoolfee']
163        self.browser.getControl("Create ticket").click()
164        self.assertMatches('...ticket created...',
165                           self.browser.contents)
166        # In state returning we can add a new school fee ticket since
167        # p_session and p_level is different
168        IWorkflowState(self.student).setState('returning')
169        self.browser.open(self.payments_path + '/addop')
170        self.browser.getControl(name="form.p_category").value = ['schoolfee']
171        self.browser.getControl("Create ticket").click()
172        # Uups, we forgot to add a session configuration for next session
173        self.assertTrue('Session configuration object is not available.'
174            in self.browser.contents)
175        configuration = createObject('waeup.SessionConfiguration')
176        configuration.academic_session = 2005
177        self.app['configuration'].addSessionConfiguration(configuration)
178        self.browser.getControl(name="form.p_category").value = ['schoolfee']
179        self.browser.getControl("Create ticket").click()
180        self.assertMatches('...ticket created...',
181                           self.browser.contents)
182
183        # In state admitted school fee can't be determined
184        IWorkflowState(self.student).setState('admitted')
185        self.browser.open(self.payments_path + '/addop')
186        self.browser.getControl(name="form.p_category").value = ['schoolfee']
187        self.browser.getControl("Create ticket").click()
188        self.assertMatches('...Wrong state...',
189                           self.browser.contents)
190
191    def test_student_payments(self):
192        # Login
193        IWorkflowState(self.student).setState('returning')
194        self.browser.open(self.login_path)
195        self.browser.getControl(name="form.login").value = self.student_id
196        self.browser.getControl(name="form.password").value = 'spwd'
197        self.browser.getControl("Login").click()
198        self.browser.open(self.student_path + '/payments')
199        self.assertTrue(
200          'Add current session payment ticket' in self.browser.contents)
201        self.assertFalse(
202          'Add previous session payment ticket' in self.browser.contents)
203        return
204
205    def test_get_returning_data(self):
206        # Student is in level 100, session 2004 with verdict A
207        utils = getUtility(IStudentsUtils)
208        self.assertEqual(utils.getReturningData(self.student),(2005, 200))
209        self.student['studycourse'].current_verdict = 'C'
210        self.assertEqual(utils.getReturningData(self.student),(2005, 110))
211        self.student['studycourse'].current_verdict = 'D'
212        self.assertEqual(utils.getReturningData(self.student),(2005, 100))
213        self.student['studycourse'].current_verdict = 'O'
214        self.assertEqual(utils.getReturningData(self.student),(2004, 110))
215        return
216
217    def test_set_payment_details(self):
218        self.app['configuration']['2004'].booking_fee = 150.0
219        self.app['configuration']['2004'].maint_fee = 180.0
220        self.app['configuration']['2004'].clearance_fee = 120.0
221        utils = getUtility(IStudentsUtils)
222
223        error, payment = utils.setPaymentDetails('schoolfee',self.student)
224        self.assertEqual(payment, None)
225        self.assertEqual(error, u'Wrong state.')
226
227        IWorkflowState(self.student).setState('cleared')
228        self.certificate.study_mode = 'pd_ft'
229        error, payment = utils.setPaymentDetails('schoolfee',self.student)
230        self.assertEqual(payment.p_level, 100)
231        self.assertEqual(payment.p_session, 2004)
232        self.assertEqual(payment.amount_auth, 70000)
233        self.assertEqual(payment.p_item, u'CERT1')
234        self.assertEqual(error, None)
235
236        IWorkflowState(self.student).setState('returning')
237        error, payment = utils.setPaymentDetails('schoolfee',self.student)
238        self.assertEqual('Session configuration object is not available.', error)
239        configuration = createObject('waeup.SessionConfiguration')
240        configuration.academic_session = 2005
241        self.app['configuration'].addSessionConfiguration(configuration)
242        error, payment = utils.setPaymentDetails('schoolfee',self.student)
243        self.assertEqual(payment.p_level, 200)
244        self.assertEqual(payment.p_session, 2005)
245        self.assertEqual(payment.amount_auth, 35300)
246        self.assertEqual(payment.p_item, u'CERT1')
247        self.assertEqual(error, None)
248
249        # UG returning students pay 70700
250        self.certificate.study_mode = 'ug_ft'
251        error, payment = utils.setPaymentDetails('schoolfee',self.student)
252        self.assertEqual(payment.amount_auth,  96700)
253        self.assertEqual(error, None)
254        # UG cleared students pay 87200
255        IWorkflowState(self.student).setState('cleared')
256        error, payment = utils.setPaymentDetails('schoolfee',self.student)
257        self.assertEqual(payment.amount_auth, 126200)
258        self.assertEqual(error, None)
259
260        # NCE student payment can be disabled by
261        # setting the base school fee to -1
262        IWorkflowState(self.student).setState('returning')
263        configuration = createObject('waeup.SessionConfiguration')
264        self.app['configuration']['2004'].school_fee_base = -1.0
265        self.certificate.study_mode = 'nce_ft'
266        error, payment = utils.setPaymentDetails('schoolfee',self.student)
267        self.assertEqual(error, u'School fee payment is disabled.')
268
269        error, payment = utils.setPaymentDetails('clearance',self.student)
270        self.assertEqual(error, u'Acceptance Fee payments not allowed.')
271        IWorkflowState(self.student).setState('cleared')
272        error, payment = utils.setPaymentDetails('clearance',self.student)
273        self.assertEqual(payment.p_level, 100)
274        self.assertEqual(payment.p_session, 2004)
275        self.assertEqual(payment.amount_auth, 120)
276        self.assertEqual(payment.p_item, u'CERT1')
277        self.assertEqual(error, None)
278
279        self.app['hostels'].accommodation_session = 2005
280        error, payment = utils.setPaymentDetails('hostel_maintenance',self.student)
281        self.assertEqual(payment, None)
282        self.assertEqual(error, 'No bed space allocated.')
283        self.app['hostels'].accommodation_session = 2004
284
285        error, payment = utils.setPaymentDetails('hostel_maintenance',self.student)
286        self.assertEqual(payment.p_level, 100)
287        self.assertEqual(payment.p_session, 2004)
288        self.assertEqual(payment.amount_auth, 876.0)
289        self.assertEqual(payment.p_item, u'My bed coordinates')
290        self.assertEqual(error, None)
291
292        #error, payment = utils.setPaymentDetails('third_semester',self.student)
293        #self.assertEqual(error, u'Amount could not be determined.')
294        #self.student['studycourse'].current_level = 300
295        #error, payment = utils.setPaymentDetails('third_semester',self.student)
296        #self.assertEqual(error, u'Amount could not be determined.')
297        #payment = createObject('waeup.StudentOnlinePayment')
298        #payment.p_category = u'schoolfee'
299        #payment.p_session = self.student.current_session
300        #payment.p_item = u'My Certificate'
301        #payment.p_id = u'anyid'
302        #self.student['payments']['anykey'] = payment
303        #payment.p_state = 'paid'
304        #payment.p_level = 300
305        #error, payment = utils.setPaymentDetails('third_semester',self.student)
306        #self.assertEqual(payment.p_level, 300)
307        #self.assertEqual(payment.p_session, 2004)
308        #self.assertEqual(payment.amount_auth, 7938)
309        #self.assertEqual(payment.p_item, u'')
310        #self.assertEqual(error, None)
311
312        self.certificate.study_mode = u'nce_sw'
313        error, payment = utils.setPaymentDetails('hostel_maintenance',self.student)
314        self.assertEqual(payment.p_level, 100)
315        self.assertEqual(payment.p_session, 2004)
316        self.assertEqual(payment.amount_auth, 547.5)  # 62.5% * 876
317        self.assertEqual(payment.p_item, u'My bed coordinates')
318        self.assertEqual(error, None)
319
320        error, payment = utils.setPaymentDetails('bed_allocation',self.student)
321        self.assertEqual(payment.p_level, 100)
322        self.assertEqual(payment.p_session, 2004)
323        self.assertEqual(payment.amount_auth, 150)
324        self.assertEqual(payment.p_item, u'regular_male_fr')
325        self.assertEqual(error, None)
326
327        error, payment = utils.setPaymentDetails('schoolfee',self.student, 2004, 100)
328        self.assertEqual(error, u'Previous session payment not yet implemented.')
329        return
330
331    def test_student_start_clearance(self):
332        self.browser.open(self.login_path)
333        self.browser.getControl(name="form.login").value = self.student_id
334        self.browser.getControl(name="form.password").value = 'spwd'
335        self.browser.getControl("Login").click()
336
337        IWorkflowInfo(self.student).fireTransition('admit')
338        self.browser.open(self.student_path + '/change_portrait')
339        image = open(SAMPLE_IMAGE, 'rb')
340        ctrl = self.browser.getControl(name='passportuploadedit')
341        file_ctrl = ctrl.mech_control
342        file_ctrl.add_file(image, filename='my_photo.jpg')
343        self.browser.getControl(
344            name='upload_passportuploadedit').click()
345        self.browser.open(self.student_path + '/start_clearance')
346        # In Okene the ug students start clearance with activation code ...
347        self.assertTrue('Activation Code:' in self.browser.contents)
348        self.browser.getControl("Start clearance now").click()
349        self.assertTrue('Activation code is invalid' in self.browser.contents)
350        # ... and nce students without.
351        self.certificate.study_mode = 'nce_ft'
352        self.browser.open(self.student_path + '/start_clearance')
353        self.assertFalse('Activation Code:' in self.browser.contents)
354        self.browser.getControl("Start clearance now").click()
355        self.assertTrue(
356            'Clearance process has been started' in self.browser.contents)
357
358    def test_open_slips(self):
359        # Managers can open clearance slip
360        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
361        self.browser.open(self.student_path + '/view_clearance')
362        self.browser.getLink("Download clearance slip").click()
363        self.assertEqual(self.browser.headers['Status'], '200 Ok')
364        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
365
366    def test_student_accommodation(self):
367        del self.student['accommodation']['2004']
368        self.certificate.study_mode = 'ug_pt'
369        # Login
370        self.browser.open(self.login_path)
371        self.browser.getControl(name="form.login").value = self.student_id
372        self.browser.getControl(name="form.password").value = 'spwd'
373        self.browser.getControl("Login").click()
374
375        # Students can book accommodation without AC ...
376        self.browser.open(self.acco_path)
377        IWorkflowInfo(self.student).fireTransition('admit')
378        self.browser.getControl("Book accommodation").click()
379        self.assertFalse('Activation Code:' in self.browser.contents)
380        self.browser.getControl("Create bed ticket").click()
381        # Bed is randomly selected but, since there is only
382        # one bed for this student, we know that
383        self.assertEqual(self.student['accommodation']['2004'].bed_coordinates,
384            'Hall 1, Block A, Room 101, Bed A (regular_male_fr)')
385        self.assertEqual(self.student['accommodation']['2004'].display_coordinates,
386            '(see payment slip)')
387        # But the bed coordinates are hidden.
388        self.assertFalse('Hall 1, Block A, Room 101, Bed A'
389            in self.browser.contents)
390        self.assertTrue('<td>(see payment slip)</td>'
391            in self.browser.contents)
392        return
393
394    def test_admission_slip(self):
395        # Login
396        IWorkflowState(self.student).setState('admitted')
397        self.browser.open(self.login_path)
398        self.browser.getControl(name="form.login").value = self.student_id
399        self.browser.getControl(name="form.password").value = 'spwd'
400        self.browser.getControl("Login").click()
401        self.assertFalse(
402          'Download admission letter' in self.browser.contents)
403        IWorkflowState(self.student).setState('clearance started')
404        self.browser.open(self.student_path)
405        self.assertTrue(
406          'Download admission letter' in self.browser.contents)
407        # Students can open admission letter
408        self.browser.getLink("Download admission letter").click()
409        self.assertEqual(self.browser.headers['Status'], '200 Ok')
410        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
411        path = os.path.join(samples_dir(), 'admission_slip_combined.pdf')
412        open(path, 'wb').write(self.browser.contents)
413        print "Sample PDF admission_slip_combined.pdf written to %s" % path
414        self.certificate.study_mode = 'pd_ft'
415        self.browser.open(self.student_path)
416        self.browser.getLink("Download admission letter").click()
417        path = os.path.join(samples_dir(), 'admission_slip.pdf')
418        open(path, 'wb').write(self.browser.contents)
419        print "Sample PDF admission_slip.pdf written to %s" % path
420        return
421
422    def test_payment_disabled(self):
423        self.certificate.study_mode = 'nce_ft'
424        IWorkflowState(self.student).setState('cleared')
425        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
426        self.browser.open(self.payments_path)
427        self.browser.getLink("Add current session payment ticket").click()
428        self.browser.getControl(name="form.p_category").value = ['schoolfee']
429        self.browser.getControl("Create ticket").click()
430        self.assertMatches('...ticket created...',
431                           self.browser.contents)
432        self.app['configuration']['2004'].payment_disabled = ['sf_nce1']
433        self.browser.open(self.payments_path)
434        self.browser.getLink("Add current session payment ticket").click()
435        self.browser.getControl(name="form.p_category").value = ['schoolfee']
436        self.browser.getControl("Create ticket").click()
437        self.assertMatches('...This category of payments has been disabled...',
438                           self.browser.contents)
439        self.certificate.study_mode = 'ug_ft'
440        self.browser.open(self.payments_path)
441        self.browser.getLink("Add current session payment ticket").click()
442        self.browser.getControl(name="form.p_category").value = ['schoolfee']
443        self.browser.getControl("Create ticket").click()
444        self.assertMatches('...ticket created...',
445                           self.browser.contents)
446        return
447
448    def test_student_course_registration(self):
449        IWorkflowState(self.student).setState('school fee paid')
450        self.browser.open(self.login_path)
451        self.browser.getControl(name="form.login").value = self.student_id
452        self.browser.getControl(name="form.password").value = 'spwd'
453        self.browser.getControl("Login").click()
454        # Now students can add the current study level
455        self.browser.getLink("Study Course").click()
456        self.browser.getLink("Add course list").click()
457        self.assertMatches('...Add current level 100 (Year 1)...',
458                           self.browser.contents)
459        self.browser.getControl("Create course list now").click()
460        # Students can open the customized pdf course registration slip
461        self.browser.open(
462            self.student_path + '/studycourse/100/course_registration_slip.pdf')
463        self.assertEqual(self.browser.headers['Status'], '200 Ok')
464        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
465        path = os.path.join(samples_dir(), 'course_registration_slip.pdf')
466        open(path, 'wb').write(self.browser.contents)
467        print "Sample PDF course_registration_slip.pdf written to %s" % path
468
469        # Students can open the examination clearance slip if they are
470        # in state courses validated
471        IWorkflowState(self.student).setState('courses validated')
472        self.browser.open(self.student_path + '/studycourse/100')
473        self.browser.getLink("Download 1st semester examination clearance slip").click()
474        self.assertEqual(self.browser.headers['Status'], '200 Ok')
475        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
476        path = os.path.join(samples_dir(), 'examination_clearance_slip_1.pdf')
477        open(path, 'wb').write(self.browser.contents)
478        print "Sample PDF examination_clearance_slip_1.pdf written to %s" % path
479        self.browser.open(self.student_path + '/studycourse/100')
480        self.browser.getLink("Download 2nd semester examination clearance slip").click()
481        self.assertEqual(self.browser.headers['Status'], '200 Ok')
482        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
483        path = os.path.join(samples_dir(), 'examination_clearance_slip_2.pdf')
484        open(path, 'wb').write(self.browser.contents)
485        print "Sample PDF examination_clearance_slip_2.pdf written to %s" % path
Note: See TracBrowser for help on using the repository browser.