source: main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/students/tests/test_browser.py @ 12634

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

Maint payment checking disabled on Dec 5th, 2014.

  • Property svn:keywords set to Id
File size: 25.3 KB
Line 
1## $Id: test_browser.py 12148 2014-12-05 10:01:59Z 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 mechanize import LinkNotFoundError
22from StringIO import StringIO
23from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo
24from zope.component.hooks import setSite, clearSite
25from zope.component import getUtility, createObject
26from zope.interface import verify
27from waeup.kofa.app import University
28from waeup.kofa.students.tests.test_browser import (
29    StudentsFullSetup, SAMPLE_IMAGE)
30from waeup.kofa.students.accommodation import BedTicket
31from waeup.kofa.testing import FunctionalTestCase
32from waeup.kofa.interfaces import (
33    IExtFileStore, IFileStoreNameChooser)
34from waeup.kofa.browser.tests.test_pdf import samples_dir
35from waeup.kofa.students.interfaces import IStudentsUtils
36from waeup.kwarapoly.testing import FunctionalLayer
37from waeup.kwarapoly.students.utils import (
38    local_nonlocal, arts_science, pt_ft)
39
40
41class StudentProcessorTest(FunctionalTestCase):
42    """Perform some batching tests.
43    """
44
45    layer = FunctionalLayer
46
47    def setUp(self):
48        super(StudentProcessorTest, self).setUp()
49        # Setup a sample site for each test
50        app = University()
51        self.dc_root = tempfile.mkdtemp()
52        app['datacenter'].setStoragePath(self.dc_root)
53
54        # Prepopulate the ZODB...
55        self.getRootFolder()['app'] = app
56        # we add the site immediately after creation to the
57        # ZODB. Catalogs and other local utilities are not setup
58        # before that step.
59        self.app = self.getRootFolder()['app']
60        # Set site here. Some of the following setup code might need
61        # to access grok.getSite() and should get our new app then
62        setSite(app)
63
64
65    def tearDown(self):
66        super(StudentProcessorTest, self).tearDown()
67        shutil.rmtree(self.workdir)
68        shutil.rmtree(self.dc_root)
69        clearSite()
70        return
71
72class StudentUITests(StudentsFullSetup):
73    """Tests for customized student class views and pages
74    """
75
76    layer = FunctionalLayer
77
78    def setUp(self):
79        super(StudentUITests, self).setUp()
80        self.certificate.study_mode = 'hnd_ft'
81        bedticket = BedTicket()
82        bedticket.booking_session = 2004
83        bedticket.bed_type = u'any bed type'
84        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
85        bedticket.bed_coordinates = u'My bed coordinates'
86        self.student['accommodation'].addBedTicket(bedticket)
87
88        self.app['configuration']['2004'].gown_fee = 150.0
89        self.app['configuration']['2004'].transfer_fee = 90.0
90        self.app['configuration']['2004'].clearance_fee = 120.0
91        self.app['configuration']['2004'].booking_fee = 150.0
92        self.app['configuration']['2004'].maint_fee = 180.0
93        self.app['configuration']['2004'].certificate_fee = 444.0
94
95    def test_manage_payments(self):
96        # Managers can add online payment tickets
97        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
98        self.browser.open(self.payments_path)
99        self.browser.getLink("Add current session payment ticket").click()
100        self.browser.getControl(name="form.p_category").value = ['schoolfee']
101        self.browser.getControl("Create ticket").click()
102        self.assertMatches('...Amount could not be determined...',
103                           self.browser.contents)
104        IWorkflowState(self.student).setState('cleared')
105        self.browser.open(self.payments_path + '/addop')
106
107        # Maint payment checking disabled on 5th Dec 2014
108        #self.browser.getControl(name="form.p_category").value = ['schoolfee']
109        #self.browser.getControl("Create ticket").click()
110        #self.assertMatches('...Book and pay for accommodation first...',
111        #                   self.browser.contents)
112        ## In KwaraPoly only returning students can create school fee payment
113        ## without having paid accommodation fee
114
115        IWorkflowState(self.student).setState('returning')
116        configuration = createObject('waeup.SessionConfiguration')
117        configuration.academic_session = 2005
118        self.app['configuration'].addSessionConfiguration(configuration)
119        self.browser.getControl(name="form.p_category").value = ['schoolfee']
120        self.browser.getControl("Create ticket").click()
121        self.assertMatches('...ticket created...',
122                           self.browser.contents)
123        ctrl = self.browser.getControl(name='val_id')
124        value = ctrl.options[0]
125        self.browser.getLink(value).click()
126        self.assertMatches('...Amount Authorized...',
127                           self.browser.contents)
128        # Managers can open payment slip
129        self.browser.getLink("Download payment slip").click()
130        self.assertEqual(self.browser.headers['Status'], '200 Ok')
131        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
132        # Set ticket paid
133        ticket = self.student['payments'].items()[0][1]
134        ticket.p_state = 'paid'
135        self.browser.open(self.payments_path + '/addop')
136        self.browser.getControl(name="form.p_category").value = ['schoolfee']
137        self.browser.getControl("Create ticket").click()
138        self.assertMatches('...This type of payment has already been made...',
139                           self.browser.contents)
140        # Remove all payments so that we can add a school fee payment again
141        keys = [i for i in self.student['payments'].keys()]
142        for payment in keys:
143            del self.student['payments'][payment]
144        self.browser.open(self.payments_path + '/addop')
145        self.browser.getControl(name="form.p_category").value = ['schoolfee']
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(name="form.p_category").value = ['carryover1']
151        self.browser.getControl("Create ticket").click()
152        self.assertMatches('...ticket created...',
153                           self.browser.contents)
154        self.browser.open(self.payments_path + '/addop')
155        self.browser.getControl(name="form.p_category").value = ['carryover2']
156        self.browser.getControl("Create ticket").click()
157        self.assertMatches('...ticket created...',
158                           self.browser.contents)
159        self.browser.open(self.payments_path + '/addop')
160        self.browser.getControl(name="form.p_category").value = ['carryover3']
161        self.browser.getControl("Create ticket").click()
162        self.assertMatches('...ticket created...',
163                           self.browser.contents)
164        self.browser.open(self.payments_path + '/addop')
165        self.browser.getControl(
166            name="form.p_category").value = ['hostel_maintenance']
167        self.browser.getControl("Create ticket").click()
168        self.assertMatches('...ticket created...',
169                           self.browser.contents)
170        self.browser.open(self.payments_path + '/addop')
171        self.browser.getControl(name="form.p_category").value = ['schoolfee']
172        self.browser.getControl("Create ticket").click()
173        self.assertMatches('...ticket created...',
174                           self.browser.contents)
175        # In state admitted school fee can't be determined
176        IWorkflowState(self.student).setState('admitted')
177        self.browser.open(self.payments_path + '/addop')
178        self.browser.getControl(name="form.p_category").value = ['schoolfee']
179        self.browser.getControl("Create ticket").click()
180        self.assertMatches('...Amount could not be determined...',
181                           self.browser.contents)
182        self.browser.open(self.payments_path + '/addop')
183        self.browser.getControl(name="form.p_category").value = ['certificate']
184        self.browser.getControl("Create ticket").click()
185        self.assertMatches('...ticket created...',
186                           self.browser.contents)
187
188    def test_student_payments(self):
189        # Login
190        IWorkflowState(self.student).setState('returning')
191        self.browser.open(self.login_path)
192        self.browser.getControl(name="form.login").value = self.student_id
193        self.browser.getControl(name="form.password").value = 'spwd'
194        self.browser.getControl("Login").click()
195        self.browser.open(self.student_path + '/payments')
196        self.assertTrue(
197          'Add current session payment ticket' in self.browser.contents)
198        self.assertFalse(
199          'Add previous session payment ticket' in self.browser.contents)
200        return
201
202    def test_get_returning_data(self):
203        # Student is in level 100, session 2004 with verdict A
204        utils = getUtility(IStudentsUtils)
205        self.assertEqual(utils.getReturningData(self.student),(2005, 200))
206        self.student['studycourse'].current_verdict = 'C'
207        self.assertEqual(utils.getReturningData(self.student),(2005, 110))
208        self.student['studycourse'].current_verdict = 'D'
209        self.assertEqual(utils.getReturningData(self.student),(2005, 100))
210        return
211
212    def test_set_payment_details(self):
213        utils = getUtility(IStudentsUtils)
214
215        error, payment = utils.setPaymentDetails('schoolfee',self.student)
216        self.assertEqual(payment, None)
217        self.assertEqual(error, u'Amount could not be determined.')
218
219        IWorkflowState(self.student).setState('cleared')
220        self.assertEqual(local_nonlocal(self.student), 'non-local')
221        self.assertEqual(arts_science(self.student), 'science')
222        self.assertEqual(pt_ft(self.student), 'ft')
223
224        # Maint payment checking disabled on 5th Dec 2014
225        #error, payment = utils.setPaymentDetails('schoolfee',self.student)
226        #self.assertEqual(error,
227        #    'Book and pay for accommodation first before making'
228        #    ' school fee payments.')
229        ## We add a fake maint. payment ticket to meet the condition
230        #maint_payment = createObject('waeup.StudentOnlinePayment')
231        #self.student['payments']['any_key'] = maint_payment
232        #maint_payment.p_category = 'hostel_maintenance'
233        #maint_payment.p_state = 'paid'
234        #maint_payment.p_session = 2004
235
236        error, payment = utils.setPaymentDetails('schoolfee',self.student)
237        self.assertEqual(payment.p_level, 100)
238        self.assertEqual(payment.p_session, 2004)
239        self.assertEqual(payment.amount_auth, 53900.0)
240        self.assertEqual(payment.p_item, u'CERT1')
241        self.assertEqual(error, None)
242
243        IWorkflowState(self.student).setState('returning')
244        error, payment = utils.setPaymentDetails('schoolfee',self.student)
245        self.assertEqual('Session configuration object is not available.', error)
246        configuration = createObject('waeup.SessionConfiguration')
247        configuration.academic_session = 2005
248        self.app['configuration'].addSessionConfiguration(configuration)
249        error, payment = utils.setPaymentDetails('schoolfee',self.student)
250        self.assertEqual(payment.p_level, 200)
251        self.assertEqual(payment.p_session, 2005)
252        self.assertEqual(payment.amount_auth, 33090.0)
253        self.assertEqual(payment.p_item, u'CERT1')
254        self.assertEqual(error, None)
255
256        configuration.penalty_ug = 5000.0
257        error, payment = utils.setPaymentDetails('schoolfee',self.student)
258        self.assertEqual(payment.amount_auth, 38090.0)
259        self.assertEqual(error, None)
260
261        error, payment = utils.setPaymentDetails('clearance',self.student)
262        self.assertEqual(payment.p_level, 100)
263        self.assertEqual(payment.p_session, 2004)
264        self.assertEqual(payment.amount_auth, 120.0)
265        self.assertEqual(payment.p_item, u'CERT1')
266        self.assertEqual(error, None)
267
268        error, payment = utils.setPaymentDetails('carryover1',self.student)
269        self.assertEqual(payment.p_level, 100)
270        self.assertEqual(payment.p_session, 2004)
271        self.assertEqual(payment.amount_auth, 6000.0)
272        self.assertEqual(payment.p_item, u'1 CarryOver')
273        self.assertEqual(payment.p_category, 'schoolfee')
274        self.assertEqual(error, None)
275
276        error, payment = utils.setPaymentDetails('carryover2',self.student)
277        self.assertEqual(payment.p_level, 100)
278        self.assertEqual(payment.p_session, 2004)
279        self.assertEqual(payment.amount_auth, 7000.0)
280        self.assertEqual(payment.p_item, u'2 CarryOvers')
281        self.assertEqual(payment.p_category, 'schoolfee')
282        self.assertEqual(error, None)
283
284        error, payment = utils.setPaymentDetails('carryover3',self.student)
285        self.assertEqual(payment.p_level, 100)
286        self.assertEqual(payment.p_session, 2004)
287        self.assertEqual(payment.amount_auth, 8000.0)
288        self.assertEqual(payment.p_item, u'3 CarryOvers')
289        self.assertEqual(payment.p_category, 'schoolfee')
290        self.assertEqual(error, None)
291
292        error, payment = utils.setPaymentDetails('hostel_maintenance',self.student)
293        self.assertEqual(payment.p_level, 100)
294        self.assertEqual(payment.p_session, 2004)
295        self.assertEqual(payment.amount_auth, 876.0)
296        self.assertEqual(payment.p_item, u'My bed coordinates')
297        self.assertEqual(error, None)
298
299        self.app['hostels']['hall-1'].maint_fee = 0.0
300        error, payment = utils.setPaymentDetails('hostel_maintenance',self.student)
301        self.assertEqual(payment.p_level, 100)
302        self.assertEqual(payment.p_session, 2004)
303        self.assertEqual(payment.amount_auth, 180.0)
304        self.assertEqual(payment.p_item, u'My bed coordinates')
305        self.assertEqual(error, None)
306
307        error, payment = utils.setPaymentDetails('bed_allocation',self.student)
308        self.assertEqual(payment.p_level, 100)
309        self.assertEqual(payment.p_session, 2004)
310        self.assertEqual(payment.amount_auth, 150.0)
311        self.assertEqual(payment.p_item, u'')
312        self.assertEqual(error, None)
313
314        error, payment = utils.setPaymentDetails('certificate',self.student)
315        self.assertEqual(payment.p_level, 100)
316        self.assertEqual(payment.p_session, 2004)
317        self.assertEqual(payment.amount_auth, 444.0)
318        self.assertEqual(payment.p_item, u'')
319        self.assertEqual(payment.p_category, 'certificate')
320        self.assertEqual(error, None)
321
322        error, payment = utils.setPaymentDetails('schoolfee',self.student, 2004, 100)
323        self.assertEqual(error, u'Previous session payment not yet implemented.')
324        return
325
326    def test_student_start_clearance(self):
327        self.browser.open(self.login_path)
328        self.browser.getControl(name="form.login").value = self.student_id
329        self.browser.getControl(name="form.password").value = 'spwd'
330        self.browser.getControl("Login").click()
331
332        IWorkflowInfo(self.student).fireTransition('admit')
333        self.browser.open(self.student_path + '/change_portrait')
334        image = open(SAMPLE_IMAGE, 'rb')
335        ctrl = self.browser.getControl(name='passportuploadedit')
336        file_ctrl = ctrl.mech_control
337        file_ctrl.add_file(image, filename='my_photo.jpg')
338        self.browser.getControl(
339            name='upload_passportuploadedit').click()
340        self.browser.open(self.student_path + '/start_clearance')
341        # In KwaraPoly the students can just start clearance without entering
342        # an activation code.
343        self.browser.getControl("Start clearance now").click()
344        self.assertMatches('...Clearance process has been started...',
345                           self.browser.contents)
346
347    def test_change_passport(self):
348        self.browser.open(self.login_path)
349        self.browser.getControl(name="form.login").value = self.student_id
350        self.browser.getControl(name="form.password").value = 'spwd'
351        self.browser.getControl("Login").click()
352
353        IWorkflowState(self.student).setState('cleared')
354        self.browser.open(self.student_path + '/change_portrait')
355        image = open(SAMPLE_IMAGE, 'rb')
356        ctrl = self.browser.getControl(name='passportuploadedit')
357        file_ctrl = ctrl.mech_control
358        file_ctrl.add_file(image, filename='my_photo.jpg')
359        self.browser.getControl(
360            name='upload_passportuploadedit').click()
361
362
363    def test_student_accommodation(self):
364        del self.student['accommodation']['2004']
365        # Login
366        self.browser.open(self.login_path)
367        self.browser.getControl(name="form.login").value = self.student_id
368        self.browser.getControl(name="form.password").value = 'spwd'
369        self.browser.getControl("Login").click()
370
371        # Students can book accommodation without AC ...
372        self.browser.open(self.acco_path)
373        IWorkflowInfo(self.student).fireTransition('admit')
374        self.browser.getLink("Book accommodation").click()
375        self.assertFalse('Activation Code:' in self.browser.contents)
376        self.browser.getControl("Create bed ticket").click()
377        # Bed is randomly selected but, since there is only
378        # one bed for this student, we know that
379        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
380                           self.browser.contents)
381        return
382
383    def test_no_beds_for_iot(self):
384        self.app['faculties']['fac1'].code = 'IOT'
385        del self.student['accommodation']['2004']
386        # Login
387        self.browser.open(self.login_path)
388        self.browser.getControl(name="form.login").value = self.student_id
389        self.browser.getControl(name="form.password").value = 'spwd'
390        self.browser.getControl("Login").click()
391
392        self.browser.open(self.acco_path)
393        IWorkflowInfo(self.student).fireTransition('admit')
394        self.browser.getLink("Book accommodation").click()
395        self.browser.getControl("Create bed ticket").click()
396        self.assertTrue('There is no free bed in your category iot_male_fr.' in
397                           self.browser.contents)
398        return
399
400    def test_admission_pdf_slips(self):
401        # Login
402        self.browser.open(self.login_path)
403        self.browser.getControl(name="form.login").value = self.student_id
404        self.browser.getControl(name="form.password").value = 'spwd'
405        self.browser.getControl("Login").click()
406        # admission slip
407        IWorkflowState(self.student).setState('school fee paid')
408        self.browser.open(self.student_path)
409        self.browser.getLink("Download admission letter").click()
410        self.assertEqual(self.browser.headers['Status'], '200 Ok')
411        self.assertEqual(self.browser.headers['Content-Type'],
412                         'application/pdf')
413        path = os.path.join(samples_dir(), 'admission_slip.pdf')
414        open(path, 'wb').write(self.browser.contents)
415        print "Sample PDF admission_slip_slip.pdf written to %s" % path
416        self.browser.open(self.student_path)
417        self.assertRaises(
418            LinkNotFoundError, self.browser.getLink, 'Download admission notification')
419        self.browser.open(self.student_path + '/admission_notification.pdf')
420        self.assertTrue('Not allowed' in self.browser.contents)
421        # admission notification
422        IWorkflowState(self.student).setState('cleared')
423        self.browser.open(self.student_path)
424        self.browser.getLink("Download admission notification").click()
425        self.assertEqual(self.browser.headers['Status'], '200 Ok')
426        self.assertEqual(self.browser.headers['Content-Type'],
427                         'application/pdf')
428        path = os.path.join(samples_dir(), 'admission_notification.pdf')
429        open(path, 'wb').write(self.browser.contents)
430        print "Sample PDF admission_notification.pdf written to %s" % path
431        self.browser.open(self.student_path)
432        self.assertRaises(
433            LinkNotFoundError, self.browser.getLink, 'Download admission letter')
434        self.browser.open(self.student_path + '/admission_slip.pdf')
435        self.assertTrue('Not allowed' in self.browser.contents)
436        return
437
438    def test_registration_pdf_slips(self):
439        # Student cant login if their password is not set
440        IWorkflowState(self.student).setState('school fee paid')
441        self.browser.open(self.login_path)
442        self.browser.getControl(name="form.login").value = self.student_id
443        self.browser.getControl(name="form.password").value = 'spwd'
444        self.browser.getControl("Login").click()
445        self.browser.getLink("Course of Study").click()
446        self.browser.getLink("Add course list").click()
447        self.assertMatches('...Add current level 100 (Year 1)...',
448                           self.browser.contents)
449        self.browser.getControl("Create course list now").click()
450        # A level with one course ticket was created
451        self.browser.getLink("100").click()
452        self.browser.getLink("Download course registration slip").click()
453        self.assertEqual(self.browser.headers['Status'], '200 Ok')
454        self.assertEqual(self.browser.headers['Content-Type'],
455                         'application/pdf')
456        path = os.path.join(samples_dir(), 'course_registration_slip.pdf')
457        open(path, 'wb').write(self.browser.contents)
458        print "Sample PDF course_registration_slip.pdf written to %s" % path
459
460        self.browser.open(self.student_path)
461        self.browser.getLink("Download registration form").click()
462        self.assertEqual(self.browser.headers['Status'], '200 Ok')
463        self.assertEqual(self.browser.headers['Content-Type'],
464                         'application/pdf')
465        path = os.path.join(samples_dir(), 'registration_slip.pdf')
466        open(path, 'wb').write(self.browser.contents)
467        print "Sample PDF registration_form.pdf written to %s" % path
468
469        return
470
471    def test_payment_disabled(self):
472        IWorkflowState(self.student).setState('returning')
473        configuration = createObject('waeup.SessionConfiguration')
474        configuration.academic_session = 2005
475        self.app['configuration'].addSessionConfiguration(configuration)
476        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
477        self.browser.open(self.payments_path)
478        self.browser.getLink("Add current session payment ticket").click()
479        self.browser.getControl(name="form.p_category").value = ['schoolfee']
480        self.browser.getControl("Create ticket").click()
481        self.assertMatches('...ticket created...',
482                           self.browser.contents)
483        self.app['configuration']['2005'].payment_disabled = ['sf_all']
484        self.browser.getLink("Add current session payment ticket").click()
485        self.browser.getControl(name="form.p_category").value = ['schoolfee']
486        self.browser.getControl("Create ticket").click()
487        self.assertMatches('...Payment temporarily disabled...',
488                           self.browser.contents)
489        self.app['configuration']['2005'].payment_disabled = ['sf_non_pg']
490        # Non-PG students can't pay ...
491        self.browser.getControl(name="form.p_category").value = ['schoolfee']
492        self.browser.getControl("Create ticket").click()
493        self.assertMatches('...Payment temporarily disabled...',
494                           self.browser.contents)
495        # ... but PG can pay.
496        self.certificate.study_mode = 'pg_ft'
497        self.browser.getControl(name="form.p_category").value = ['schoolfee']
498        self.browser.getControl("Create ticket").click()
499        self.assertMatches('...ticket created...',
500                           self.browser.contents)
501        return
502
503    def test_student_course_registration(self):
504        # Student cant login if their password is not set
505        IWorkflowState(self.student).setState('school fee paid')
506        self.student['studycourse'].current_level = 200
507        self.browser.open(self.login_path)
508        self.browser.getControl(name="form.login").value = self.student_id
509        self.browser.getControl(name="form.password").value = 'spwd'
510        self.browser.getControl("Login").click()
511        self.browser.open(self.student_path + '/studycourse/add')
512        # Now students can add the current study level
513        self.assertMatches('...Add current level 200 (Year 2)...',
514                           self.browser.contents)
515        self.browser.getControl("Create course list now").click()
516        self.browser.getLink("200").click()
517        self.browser.getLink("Edit course list").click()
518        self.browser.getLink("here").click()
519        self.browser.getControl(name="form.course").value = ['COURSE1']
520        self.course.credits = 100000
521        self.browser.getControl("Add course ticket").click()
522        self.assertFalse(
523            'Total credits exceed ' in self.browser.contents)
524        self.assertEqual(
525            self.student['studycourse']['200']['COURSE1'].course.credits, 100000)
526        self.browser.getControl("Register course list").click()
527        self.assertTrue('Course list has been registered' in self.browser.contents)
528        self.assertEqual(self.student.state, 'courses registered')
529        return
Note: See TracBrowser for help on using the repository browser.