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

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

Rename 'Study Course', 'Phone', 'Email', 'Faculty'.

Edit text on slips.

  • Property svn:keywords set to Id
File size: 23.7 KB
Line 
1## $Id: test_browser.py 11873 2014-10-22 14:11:24Z 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        self.browser.getControl(name="form.p_category").value = ['schoolfee']
107        self.browser.getControl("Create ticket").click()
108        self.assertMatches('...Book and pay for accommodation first...',
109                           self.browser.contents)
110
111        # In KwaraPoly only returning students can create school fee payment
112        # without having paid accommodation fee
113        IWorkflowState(self.student).setState('returning')
114        configuration = createObject('waeup.SessionConfiguration')
115        configuration.academic_session = 2005
116        self.app['configuration'].addSessionConfiguration(configuration)
117        self.browser.getControl(name="form.p_category").value = ['schoolfee']
118        self.browser.getControl("Create ticket").click()
119        self.assertMatches('...ticket created...',
120                           self.browser.contents)
121        ctrl = self.browser.getControl(name='val_id')
122        value = ctrl.options[0]
123        self.browser.getLink(value).click()
124        self.assertMatches('...Amount Authorized...',
125                           self.browser.contents)
126        # Managers can open payment slip
127        self.browser.getLink("Download payment slip").click()
128        self.assertEqual(self.browser.headers['Status'], '200 Ok')
129        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
130        # Set ticket paid
131        ticket = self.student['payments'].items()[0][1]
132        ticket.p_state = 'paid'
133        self.browser.open(self.payments_path + '/addop')
134        self.browser.getControl(name="form.p_category").value = ['schoolfee']
135        self.browser.getControl("Create ticket").click()
136        self.assertMatches('...This type of payment has already been made...',
137                           self.browser.contents)
138        # Remove all payments so that we can add a school fee payment again
139        keys = [i for i in self.student['payments'].keys()]
140        for payment in keys:
141            del self.student['payments'][payment]
142        self.browser.open(self.payments_path + '/addop')
143        self.browser.getControl(name="form.p_category").value = ['schoolfee']
144        self.browser.getControl("Create ticket").click()
145        self.assertMatches('...ticket created...',
146                           self.browser.contents)
147        self.browser.open(self.payments_path + '/addop')
148        self.browser.getControl(name="form.p_category").value = ['carryover1']
149        self.browser.getControl("Create ticket").click()
150        self.assertMatches('...ticket created...',
151                           self.browser.contents)
152        self.browser.open(self.payments_path + '/addop')
153        self.browser.getControl(name="form.p_category").value = ['carryover2']
154        self.browser.getControl("Create ticket").click()
155        self.assertMatches('...ticket created...',
156                           self.browser.contents)
157        self.browser.open(self.payments_path + '/addop')
158        self.browser.getControl(name="form.p_category").value = ['carryover3']
159        self.browser.getControl("Create ticket").click()
160        self.assertMatches('...ticket created...',
161                           self.browser.contents)
162        self.browser.open(self.payments_path + '/addop')
163        self.browser.getControl(
164            name="form.p_category").value = ['hostel_maintenance']
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 = ['schoolfee']
170        self.browser.getControl("Create ticket").click()
171        self.assertMatches('...ticket created...',
172                           self.browser.contents)
173        # In state admitted school fee can't be determined
174        IWorkflowState(self.student).setState('admitted')
175        self.browser.open(self.payments_path + '/addop')
176        self.browser.getControl(name="form.p_category").value = ['schoolfee']
177        self.browser.getControl("Create ticket").click()
178        self.assertMatches('...Amount could not be determined...',
179                           self.browser.contents)
180        self.browser.open(self.payments_path + '/addop')
181        self.browser.getControl(name="form.p_category").value = ['certificate']
182        self.browser.getControl("Create ticket").click()
183        self.assertMatches('...ticket created...',
184                           self.browser.contents)
185
186    def test_student_payments(self):
187        # Login
188        IWorkflowState(self.student).setState('returning')
189        self.browser.open(self.login_path)
190        self.browser.getControl(name="form.login").value = self.student_id
191        self.browser.getControl(name="form.password").value = 'spwd'
192        self.browser.getControl("Login").click()
193        self.browser.open(self.student_path + '/payments')
194        self.assertTrue(
195          'Add current session payment ticket' in self.browser.contents)
196        self.assertFalse(
197          'Add previous session payment ticket' in self.browser.contents)
198        return
199
200    def test_get_returning_data(self):
201        # Student is in level 100, session 2004 with verdict A
202        utils = getUtility(IStudentsUtils)
203        self.assertEqual(utils.getReturningData(self.student),(2005, 200))
204        self.student['studycourse'].current_verdict = 'C'
205        self.assertEqual(utils.getReturningData(self.student),(2005, 110))
206        self.student['studycourse'].current_verdict = 'D'
207        self.assertEqual(utils.getReturningData(self.student),(2005, 100))
208        return
209
210    def test_set_payment_details(self):
211        utils = getUtility(IStudentsUtils)
212
213        error, payment = utils.setPaymentDetails('schoolfee',self.student)
214        self.assertEqual(payment, None)
215        self.assertEqual(error, u'Amount could not be determined.')
216
217        IWorkflowState(self.student).setState('cleared')
218        self.assertEqual(local_nonlocal(self.student), 'non-local')
219        self.assertEqual(arts_science(self.student), 'science')
220        self.assertEqual(pt_ft(self.student), 'ft')
221
222        error, payment = utils.setPaymentDetails('schoolfee',self.student)
223        self.assertEqual(error,
224            'Book and pay for accommodation first before making'
225            ' school fee payments.')
226        # We add a fake maint. payment ticket to meet the condition
227        maint_payment = createObject('waeup.StudentOnlinePayment')
228        self.student['payments']['any_key'] = maint_payment
229        maint_payment.p_category = 'hostel_maintenance'
230        maint_payment.p_state = 'paid'
231        maint_payment.p_session = 2004
232        error, payment = utils.setPaymentDetails('schoolfee',self.student)
233        self.assertEqual(payment.p_level, 100)
234        self.assertEqual(payment.p_session, 2004)
235        self.assertEqual(payment.amount_auth, 53900.0)
236        self.assertEqual(payment.p_item, u'CERT1')
237        self.assertEqual(error, None)
238
239        IWorkflowState(self.student).setState('returning')
240        error, payment = utils.setPaymentDetails('schoolfee',self.student)
241        self.assertEqual('Session configuration object is not available.', error)
242        configuration = createObject('waeup.SessionConfiguration')
243        configuration.academic_session = 2005
244        self.app['configuration'].addSessionConfiguration(configuration)
245        error, payment = utils.setPaymentDetails('schoolfee',self.student)
246        self.assertEqual(payment.p_level, 200)
247        self.assertEqual(payment.p_session, 2005)
248        self.assertEqual(payment.amount_auth, 33090.0)
249        self.assertEqual(payment.p_item, u'CERT1')
250        self.assertEqual(error, None)
251
252        configuration.penalty_ug = 5000.0
253        error, payment = utils.setPaymentDetails('schoolfee',self.student)
254        self.assertEqual(payment.amount_auth, 38090.0)
255        self.assertEqual(error, None)
256
257        error, payment = utils.setPaymentDetails('clearance',self.student)
258        self.assertEqual(payment.p_level, 100)
259        self.assertEqual(payment.p_session, 2004)
260        self.assertEqual(payment.amount_auth, 120.0)
261        self.assertEqual(payment.p_item, u'CERT1')
262        self.assertEqual(error, None)
263
264        error, payment = utils.setPaymentDetails('carryover1',self.student)
265        self.assertEqual(payment.p_level, 100)
266        self.assertEqual(payment.p_session, 2004)
267        self.assertEqual(payment.amount_auth, 6000.0)
268        self.assertEqual(payment.p_item, u'1 CarryOver')
269        self.assertEqual(payment.p_category, 'schoolfee')
270        self.assertEqual(error, None)
271
272        error, payment = utils.setPaymentDetails('carryover2',self.student)
273        self.assertEqual(payment.p_level, 100)
274        self.assertEqual(payment.p_session, 2004)
275        self.assertEqual(payment.amount_auth, 7000.0)
276        self.assertEqual(payment.p_item, u'2 CarryOvers')
277        self.assertEqual(payment.p_category, 'schoolfee')
278        self.assertEqual(error, None)
279
280        error, payment = utils.setPaymentDetails('carryover3',self.student)
281        self.assertEqual(payment.p_level, 100)
282        self.assertEqual(payment.p_session, 2004)
283        self.assertEqual(payment.amount_auth, 8000.0)
284        self.assertEqual(payment.p_item, u'3 CarryOvers')
285        self.assertEqual(payment.p_category, 'schoolfee')
286        self.assertEqual(error, None)
287
288        error, payment = utils.setPaymentDetails('hostel_maintenance',self.student)
289        self.assertEqual(payment.p_level, 100)
290        self.assertEqual(payment.p_session, 2004)
291        self.assertEqual(payment.amount_auth, 876.0)
292        self.assertEqual(payment.p_item, u'My bed coordinates')
293        self.assertEqual(error, None)
294
295        self.app['hostels']['hall-1'].maint_fee = 0.0
296        error, payment = utils.setPaymentDetails('hostel_maintenance',self.student)
297        self.assertEqual(payment.p_level, 100)
298        self.assertEqual(payment.p_session, 2004)
299        self.assertEqual(payment.amount_auth, 180.0)
300        self.assertEqual(payment.p_item, u'My bed coordinates')
301        self.assertEqual(error, None)
302
303        error, payment = utils.setPaymentDetails('bed_allocation',self.student)
304        self.assertEqual(payment.p_level, 100)
305        self.assertEqual(payment.p_session, 2004)
306        self.assertEqual(payment.amount_auth, 150.0)
307        self.assertEqual(payment.p_item, u'')
308        self.assertEqual(error, None)
309
310        error, payment = utils.setPaymentDetails('certificate',self.student)
311        self.assertEqual(payment.p_level, 100)
312        self.assertEqual(payment.p_session, 2004)
313        self.assertEqual(payment.amount_auth, 444.0)
314        self.assertEqual(payment.p_item, u'')
315        self.assertEqual(payment.p_category, 'certificate')
316        self.assertEqual(error, None)
317
318        error, payment = utils.setPaymentDetails('schoolfee',self.student, 2004, 100)
319        self.assertEqual(error, u'Previous session payment not yet implemented.')
320        return
321
322    def test_student_start_clearance(self):
323        self.browser.open(self.login_path)
324        self.browser.getControl(name="form.login").value = self.student_id
325        self.browser.getControl(name="form.password").value = 'spwd'
326        self.browser.getControl("Login").click()
327
328        IWorkflowInfo(self.student).fireTransition('admit')
329        self.browser.open(self.student_path + '/change_portrait')
330        image = open(SAMPLE_IMAGE, 'rb')
331        ctrl = self.browser.getControl(name='passportuploadedit')
332        file_ctrl = ctrl.mech_control
333        file_ctrl.add_file(image, filename='my_photo.jpg')
334        self.browser.getControl(
335            name='upload_passportuploadedit').click()
336        self.browser.open(self.student_path + '/start_clearance')
337        # In KwaraPoly the students can just start clearance without entering
338        # an activation code.
339        self.browser.getControl("Start clearance now").click()
340        self.assertMatches('...Clearance process has been started...',
341                           self.browser.contents)
342
343    def test_change_passport(self):
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
349        IWorkflowState(self.student).setState('cleared')
350        self.browser.open(self.student_path + '/change_portrait')
351        image = open(SAMPLE_IMAGE, 'rb')
352        ctrl = self.browser.getControl(name='passportuploadedit')
353        file_ctrl = ctrl.mech_control
354        file_ctrl.add_file(image, filename='my_photo.jpg')
355        self.browser.getControl(
356            name='upload_passportuploadedit').click()
357
358
359    def test_student_accommodation(self):
360        del self.student['accommodation']['2004']
361        # Login
362        self.browser.open(self.login_path)
363        self.browser.getControl(name="form.login").value = self.student_id
364        self.browser.getControl(name="form.password").value = 'spwd'
365        self.browser.getControl("Login").click()
366
367        # Students can book accommodation without AC ...
368        self.browser.open(self.acco_path)
369        IWorkflowInfo(self.student).fireTransition('admit')
370        self.browser.getLink("Book accommodation").click()
371        self.assertFalse('Activation Code:' in self.browser.contents)
372        self.browser.getControl("Create bed ticket").click()
373        # Bed is randomly selected but, since there is only
374        # one bed for this student, we know that
375        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
376                           self.browser.contents)
377        return
378
379    def test_no_beds_for_itch(self):
380        self.app['faculties']['fac1'].code = 'ITCH'
381        del self.student['accommodation']['2004']
382        # Login
383        self.browser.open(self.login_path)
384        self.browser.getControl(name="form.login").value = self.student_id
385        self.browser.getControl(name="form.password").value = 'spwd'
386        self.browser.getControl("Login").click()
387
388        self.browser.open(self.acco_path)
389        IWorkflowInfo(self.student).fireTransition('admit')
390        self.browser.getLink("Book accommodation").click()
391        self.browser.getControl("Create bed ticket").click()
392        self.assertTrue('There is no free bed in your category itch_male_fr.' in
393                           self.browser.contents)
394        return
395
396    def test_admission_pdf_slips(self):
397        # Login
398        self.browser.open(self.login_path)
399        self.browser.getControl(name="form.login").value = self.student_id
400        self.browser.getControl(name="form.password").value = 'spwd'
401        self.browser.getControl("Login").click()
402        # admission slip
403        IWorkflowState(self.student).setState('school fee paid')
404        self.browser.open(self.student_path)
405        self.browser.getLink("Download admission letter").click()
406        self.assertEqual(self.browser.headers['Status'], '200 Ok')
407        self.assertEqual(self.browser.headers['Content-Type'],
408                         'application/pdf')
409        path = os.path.join(samples_dir(), 'admission_slip.pdf')
410        open(path, 'wb').write(self.browser.contents)
411        print "Sample PDF admission_slip_slip.pdf written to %s" % path
412        self.browser.open(self.student_path)
413        self.assertRaises(
414            LinkNotFoundError, self.browser.getLink, 'Download admission notification')
415        self.browser.open(self.student_path + '/admission_notification.pdf')
416        self.assertTrue('Not allowed' in self.browser.contents)
417        # admission notification
418        IWorkflowState(self.student).setState('cleared')
419        self.browser.open(self.student_path)
420        self.browser.getLink("Download admission notification").click()
421        self.assertEqual(self.browser.headers['Status'], '200 Ok')
422        self.assertEqual(self.browser.headers['Content-Type'],
423                         'application/pdf')
424        path = os.path.join(samples_dir(), 'admission_notification.pdf')
425        open(path, 'wb').write(self.browser.contents)
426        print "Sample PDF admission_notification.pdf written to %s" % path
427        self.browser.open(self.student_path)
428        self.assertRaises(
429            LinkNotFoundError, self.browser.getLink, 'Download admission letter')
430        self.browser.open(self.student_path + '/admission_slip.pdf')
431        self.assertTrue('Not allowed' in self.browser.contents)
432        return
433
434    def test_registration_pdf_slips(self):
435        # Student cant login if their password is not set
436        IWorkflowState(self.student).setState('school fee paid')
437        self.browser.open(self.login_path)
438        self.browser.getControl(name="form.login").value = self.student_id
439        self.browser.getControl(name="form.password").value = 'spwd'
440        self.browser.getControl("Login").click()
441        self.browser.getLink("Course of Study").click()
442        self.browser.getLink("Add course list").click()
443        self.assertMatches('...Add current level 100 (Year 1)...',
444                           self.browser.contents)
445        self.browser.getControl("Create course list now").click()
446        # A level with one course ticket was created
447        self.browser.getLink("100").click()
448        self.browser.getLink("Download course registration slip").click()
449        self.assertEqual(self.browser.headers['Status'], '200 Ok')
450        self.assertEqual(self.browser.headers['Content-Type'],
451                         'application/pdf')
452        path = os.path.join(samples_dir(), 'course_registration_slip.pdf')
453        open(path, 'wb').write(self.browser.contents)
454        print "Sample PDF course_registration_slip.pdf written to %s" % path
455
456        self.browser.open(self.student_path)
457        self.browser.getLink("Download registration form").click()
458        self.assertEqual(self.browser.headers['Status'], '200 Ok')
459        self.assertEqual(self.browser.headers['Content-Type'],
460                         'application/pdf')
461        path = os.path.join(samples_dir(), 'registration_slip.pdf')
462        open(path, 'wb').write(self.browser.contents)
463        print "Sample PDF registration_form.pdf written to %s" % path
464
465        return
466
467    def test_payment_disabled(self):
468        IWorkflowState(self.student).setState('returning')
469        configuration = createObject('waeup.SessionConfiguration')
470        configuration.academic_session = 2005
471        self.app['configuration'].addSessionConfiguration(configuration)
472        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
473        self.browser.open(self.payments_path)
474        self.browser.getLink("Add current session payment ticket").click()
475        self.browser.getControl(name="form.p_category").value = ['schoolfee']
476        self.browser.getControl("Create ticket").click()
477        self.assertMatches('...ticket created...',
478                           self.browser.contents)
479        self.app['configuration']['2005'].payment_disabled = ['sf_all']
480        self.browser.getLink("Add current session payment ticket").click()
481        self.browser.getControl(name="form.p_category").value = ['schoolfee']
482        self.browser.getControl("Create ticket").click()
483        self.assertMatches('...Payment temporarily disabled...',
484                           self.browser.contents)
485        self.app['configuration']['2005'].payment_disabled = ['sf_non_pg']
486        # Non-PG students can't pay ...
487        self.browser.getControl(name="form.p_category").value = ['schoolfee']
488        self.browser.getControl("Create ticket").click()
489        self.assertMatches('...Payment temporarily disabled...',
490                           self.browser.contents)
491        # ... but PG can pay.
492        self.certificate.study_mode = 'pg_ft'
493        self.browser.getControl(name="form.p_category").value = ['schoolfee']
494        self.browser.getControl("Create ticket").click()
495        self.assertMatches('...ticket created...',
496                           self.browser.contents)
497        return
Note: See TracBrowser for help on using the repository browser.