source: main/waeup.futminna/trunk/src/waeup/futminna/students/tests/test_browser.py @ 8721

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

Merged with r8720.

  • Property svn:keywords set to Id
File size: 18.3 KB
Line 
1## $Id: test_browser.py 8721 2012-06-14 08:06: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
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 StudentsFullSetup
28from waeup.kofa.testing import FunctionalTestCase
29from waeup.kofa.interfaces import (
30    IExtFileStore, IFileStoreNameChooser)
31from waeup.kofa.students.batching import StudentProcessor
32from waeup.kofa.students.interfaces import IStudentsUtils
33from waeup.futminna.students.batching import CustomStudentProcessor
34from waeup.futminna.testing import FunctionalLayer
35from waeup.futminna.students.interfaces import (
36    ICustomStudentStudyCourse, ICustomStudent,
37    ICustomStudentStudyLevel, ICustomCourseTicket)
38
39
40STUDENT_SAMPLE_DATA = open(
41    os.path.join(os.path.dirname(__file__), 'sample_student_data.csv'),
42    'rb').read()
43
44STUDENT_HEADER_FIELDS = STUDENT_SAMPLE_DATA.split(
45    '\n')[0].split(',')
46
47class StudentProcessorTest(FunctionalTestCase):
48    """Perform some batching tests.
49    """
50
51    layer = FunctionalLayer
52
53    def setUp(self):
54        super(StudentProcessorTest, self).setUp()
55        # Setup a sample site for each test
56        app = University()
57        self.dc_root = tempfile.mkdtemp()
58        app['datacenter'].setStoragePath(self.dc_root)
59
60        # Prepopulate the ZODB...
61        self.getRootFolder()['app'] = app
62        # we add the site immediately after creation to the
63        # ZODB. Catalogs and other local utilities are not setup
64        # before that step.
65        self.app = self.getRootFolder()['app']
66        # Set site here. Some of the following setup code might need
67        # to access grok.getSite() and should get our new app then
68        setSite(app)
69
70        self.processor_base = StudentProcessor()
71        self.processor = CustomStudentProcessor()
72        self.workdir = tempfile.mkdtemp()
73        self.csv_file = os.path.join(self.workdir, 'sample_student_data.csv')
74        open(self.csv_file, 'wb').write(STUDENT_SAMPLE_DATA)
75
76    def tearDown(self):
77        super(StudentProcessorTest, self).tearDown()
78        shutil.rmtree(self.workdir)
79        shutil.rmtree(self.dc_root)
80        clearSite()
81        return
82
83    def test_import(self):
84        # We have an empty column 'date_of_birth' in  the import file.
85        # The original processor will fail because 'date_of_birth' is required
86        # in the base package.
87        num, num_warns, fin_file, fail_file = self.processor_base.doImport(
88            self.csv_file, STUDENT_HEADER_FIELDS)
89        self.assertEqual(num_warns,3)
90        assert len(self.app['students'].keys()) == 0
91        # The customized processor does not complain since 'date_of_birth' is
92        # not required in the custom package.
93        num, num_warns, fin_file, fail_file = self.processor.doImport(
94            self.csv_file, STUDENT_HEADER_FIELDS)
95        #print open(fail_file).read()
96        self.assertEqual(num_warns,0)
97        assert len(self.app['students'].keys()) == 3
98        shutil.rmtree(os.path.dirname(fin_file))
99
100
101class StudentUITests(StudentsFullSetup):
102    """Tests for customized student class views and pages
103    """
104
105    layer = FunctionalLayer
106
107    def test_classes(self):
108        # Let's see if objects created in the customized
109        # portal really implement the customized interfaces
110        verify.verifyObject(ICustomStudent, self.student)
111        verify.verifyObject(
112            ICustomStudentStudyCourse, self.student['studycourse'])
113        studylevel = createObject(u'waeup.StudentStudyLevel')
114        verify.verifyObject(ICustomStudentStudyLevel, studylevel)
115        ticket = createObject(u'waeup.CourseTicket')
116        verify.verifyObject(ICustomCourseTicket, ticket)
117        IWorkflowState(self.student).setState('returning')
118        # Let's see if next_session_allowed works as expected
119        # A, ug_ft, 100
120        self.assertTrue(self.student['studycourse'].next_session_allowed)
121        # O, ug_ft, 100
122        self.student['studycourse'].current_verdict = 'O'
123        self.assertTrue(self.student['studycourse'].next_session_allowed)
124        # O, ug_ft, 200
125        self.student['studycourse'].current_level = 200
126        self.assertFalse(self.student['studycourse'].next_session_allowed)
127        # O, de_ft, 200
128        self.student['studycourse'].certificate.study_mode = 'de_ft'
129        self.assertTrue(self.student['studycourse'].next_session_allowed)
130        # O, ph_ft, 300
131        self.student['studycourse'].certificate.study_mode = 'ph_ft'
132        self.student['studycourse'].current_level = 300
133        self.assertTrue(self.student['studycourse'].next_session_allowed)
134        # O, ph_ft, 400
135        self.student['studycourse'].current_level = 400
136        self.assertFalse(self.student['studycourse'].next_session_allowed)
137
138        # Now we convert the certificate into a postgraduate certificate
139        IWorkflowState(self.student).setState('school fee paid')
140        self.certificate.study_mode = 'pg_ft'
141        # ... and voila next session registration is allowed
142        self.assertTrue(self.student['studycourse'].next_session_allowed)
143
144    def test_manage_access(self):
145        # Managers can access the pages of students
146        # and can perform actions
147        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
148        # The student created in the base package is an ug student
149        self.browser.open(self.student_path)
150        self.browser.getLink("Clearance Data").click()
151        self.assertEqual(self.browser.headers['Status'], '200 Ok')
152        self.assertEqual(self.browser.url, self.clearance_path)
153        self.browser.getLink("Manage").click()
154        self.assertEqual(self.browser.headers['Status'], '200 Ok')
155        self.assertEqual(self.browser.url, self.manage_clearance_path)
156        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
157        self.browser.getControl("Save").click()
158        self.assertMatches('...Form has been saved...',
159                           self.browser.contents)
160        self.assertMatches('...First Sitting Record...',
161                           self.browser.contents)
162        # Managers can open clearance slip of ug students
163        self.browser.open(self.student_path + '/clearance.pdf')
164        self.assertEqual(self.browser.headers['Status'], '200 Ok')
165        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
166        # There is no pg field in the clearance form
167        self.assertFalse('Second Higher Education Record'
168            in self.browser.contents)
169        # Now we change the study mode ...
170        self.certificate.study_mode = 'pg_ft'
171        self.browser.open(self.clearance_path)
172        # ... and additional pg clearance fields appear
173        self.assertMatches('...Second Higher Education Record...',
174                           self.browser.contents)
175        # But also fields from the ug form are displayed
176        self.assertMatches('...First Sitting Record...',
177                           self.browser.contents)
178        # Managers can open clearance slip of pg students
179        self.browser.open(self.student_path + '/clearance.pdf')
180        self.assertEqual(self.browser.headers['Status'], '200 Ok')
181        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
182
183    def test_manage_payments(self):
184        # Add missing configuration data
185        self.app['configuration']['2004'].gown_fee = 150.0
186        self.app['configuration']['2004'].transfer_fee = 90.0
187        #self.app['configuration']['2004'].clearance_fee = 120.0
188        self.app['configuration']['2004'].booking_fee = 150.0
189        self.app['configuration']['2004'].maint_fee = 180.0
190
191        # Managers can add online payment tickets
192        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
193        self.browser.open(self.payments_path)
194        self.browser.getControl("Add online payment ticket").click()
195        self.browser.getControl("Create ticket").click()
196        self.assertMatches('...Amount could not be determined...',
197                           self.browser.contents)
198        IWorkflowState(self.student).setState('cleared')
199        self.browser.open(self.payments_path + '/addop')
200        self.browser.getControl("Create ticket").click()
201        self.assertMatches('...ticket created...',
202                           self.browser.contents)
203        ctrl = self.browser.getControl(name='val_id')
204        value = ctrl.options[0]
205        self.browser.getLink(value).click()
206        self.assertMatches('...Amount Authorized...',
207                           self.browser.contents)
208        # Managers can open payment slip
209        self.browser.getLink("Download payment slip").click()
210        self.assertEqual(self.browser.headers['Status'], '200 Ok')
211        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
212        # Set ticket paid
213        ticket = self.student['payments'].items()[0][1]
214        ticket.p_state = 'paid'
215        self.browser.open(self.payments_path + '/addop')
216        self.browser.getControl("Create ticket").click()
217        self.assertMatches('...This type of payment has already been made...',
218                           self.browser.contents)
219        # Remove all payments so that we can add a school fee payment again
220        keys = [i for i in self.student['payments'].keys()]
221        for payment in keys:
222            del self.student['payments'][payment]
223        self.browser.open(self.payments_path + '/addop')
224        self.browser.getControl("Create ticket").click()
225        self.assertMatches('...ticket created...',
226                           self.browser.contents)
227        self.browser.open(self.payments_path + '/addop')
228        self.browser.getControl(name="form.p_category").value = ['gown']
229        self.browser.getControl("Create ticket").click()
230        self.assertMatches('...ticket created...',
231                           self.browser.contents)
232        self.browser.open(self.payments_path + '/addop')
233        self.browser.getControl(name="form.p_category").value = ['transfer']
234        self.browser.getControl("Create ticket").click()
235        self.assertMatches('...ticket created...',
236                           self.browser.contents)
237        self.browser.open(self.payments_path + '/addop')
238        self.browser.getControl(
239            name="form.p_category").value = ['bed_allocation']
240        self.browser.getControl("Create ticket").click()
241        self.assertMatches('...ticket created...',
242                           self.browser.contents)
243        self.browser.open(self.payments_path + '/addop')
244        self.browser.getControl(
245            name="form.p_category").value = ['hostel_maintenance']
246        self.browser.getControl("Create ticket").click()
247        self.assertMatches('...ticket created...',
248                           self.browser.contents)
249        self.browser.open(self.payments_path + '/addop')
250        self.browser.getControl(name="form.p_category").value = ['clearance']
251        self.browser.getControl("Create ticket").click()
252        self.assertMatches('...ticket created...',
253                           self.browser.contents)
254        self.browser.open(self.payments_path + '/addop')
255        self.browser.getControl(name="form.p_category").value = ['schoolfee']
256        self.browser.getControl("Create ticket").click()
257        self.assertMatches('...ticket created...',
258                           self.browser.contents)
259        # In state returning we can add a new school fee ticket since
260        # p_session and p_level is different
261        IWorkflowState(self.student).setState('returning')
262        self.browser.open(self.payments_path + '/addop')
263        self.browser.getControl(name="form.p_category").value = ['schoolfee']
264        self.browser.getControl("Create ticket").click()
265        self.assertMatches('...ticket created...',
266                           self.browser.contents)
267        # In state admitted school fee can't be determined
268        IWorkflowState(self.student).setState('admitted')
269        self.browser.open(self.payments_path + '/addop')
270        self.browser.getControl(name="form.p_category").value = ['schoolfee']
271        self.browser.getControl("Create ticket").click()
272        self.assertMatches('...Amount could not be determined...',
273                           self.browser.contents)
274
275        # If the session configuration doesn't exist an error message will
276        # be shown. No other requirement is being checked.
277        del self.app['configuration']['2004']
278        self.browser.open(self.payments_path)
279        self.browser.getControl("Add online payment ticket").click()
280        self.browser.getControl("Create ticket").click()
281        self.assertMatches('...Session configuration object is not...',
282                           self.browser.contents)
283
284    def test_student_access(self):
285        # Students can edit clearance data
286        IWorkflowState(self.student).setState('cleared')
287        self.student.clearance_locked = False
288        self.browser.open(self.login_path)
289        self.browser.getControl(name="form.login").value = self.student_id
290        self.browser.getControl(name="form.password").value = 'spwd'
291        self.browser.getControl("Login").click()
292        # Even in state admitted students can't change the portait if
293        # application slip exists.
294        IWorkflowState(self.student).setState('admitted')
295        self.browser.open(self.student_path)
296        self.assertTrue('Change portrait' in self.browser.contents)
297        file_store = getUtility(IExtFileStore)
298        applicant_slip = 'My application slip'
299        file_id = IFileStoreNameChooser(self.student).chooseName(
300            attr="application_slip.pdf")
301        file_store.createFile(file_id, StringIO(applicant_slip))
302        self.browser.open(self.student_path)
303        self.assertFalse('Change portrait' in self.browser.contents)
304        self.browser.open(self.student_path + '/change_portrait')
305        self.assertTrue('The requested form is locked' in self.browser.contents)
306        # Student can view and edit clearance data
307        self.browser.getLink("Clearance Data").click()
308        self.browser.getLink("Edit").click()
309        self.assertTrue('Save' in self.browser.contents)
310
311    def test_get_returning_data(self):
312        # Student is in level 100, session 2004 with verdict A
313        utils = getUtility(IStudentsUtils)
314        self.assertEqual(utils.getReturningData(self.student),(2005, 200))
315        self.student['studycourse'].current_verdict = 'C'
316        self.assertEqual(utils.getReturningData(self.student),(2005, 110))
317        self.student['studycourse'].current_verdict = 'D'
318        self.assertEqual(utils.getReturningData(self.student),(2005, 100))
319        return
320
321    def test_set_payment_details(self):
322        self.app['configuration']['2004'].gown_fee = 150.0
323        self.app['configuration']['2004'].transfer_fee = 90.0
324        self.app['configuration']['2004'].booking_fee = 150.0
325        self.app['configuration']['2004'].maint_fee = 180.0
326        utils = getUtility(IStudentsUtils)
327
328        error, payment = utils.setPaymentDetails('schoolfee',self.student)
329        self.assertEqual(payment, None)
330        self.assertEqual(error, u'Amount could not be determined.')
331
332        IWorkflowState(self.student).setState('cleared')
333        error, payment = utils.setPaymentDetails('schoolfee',self.student)
334        self.assertEqual(payment.p_level, 100)
335        self.assertEqual(payment.p_session, 2004)
336        self.assertEqual(payment.amount_auth, 40000.0)
337        self.assertEqual(payment.p_item, u'CERT1')
338        self.assertEqual(error, None)
339
340        # Add penalty fee.
341        self.app['configuration']['2004'].penalty_ug = 99.0
342        error, payment = utils.setPaymentDetails('schoolfee',self.student)
343        self.assertEqual(payment.amount_auth, 40099.0)
344
345        IWorkflowState(self.student).setState('returning')
346        error, payment = utils.setPaymentDetails('schoolfee',self.student)
347        self.assertEqual(payment.p_level, 200)
348        self.assertEqual(payment.p_session, 2005)
349        self.assertEqual(payment.amount_auth, 20099.0)
350        self.assertEqual(payment.p_item, u'CERT1')
351        self.assertEqual(error, None)
352
353        error, payment = utils.setPaymentDetails('clearance',self.student)
354        self.assertEqual(payment.p_level, 100)
355        self.assertEqual(payment.p_session, 2004)
356        self.assertEqual(payment.amount_auth, 34250.0)
357        self.assertEqual(payment.p_item, u'CERT1')
358        self.assertEqual(error, None)
359
360        error, payment = utils.setPaymentDetails('gown',self.student)
361        self.assertEqual(payment.p_level, 100)
362        self.assertEqual(payment.p_session, 2004)
363        self.assertEqual(payment.amount_auth, 150.0)
364        self.assertEqual(payment.p_item, u'')
365        self.assertEqual(error, None)
366
367        error, payment = utils.setPaymentDetails('hostel_maintenance',self.student)
368        self.assertEqual(payment.p_level, 100)
369        self.assertEqual(payment.p_session, 2004)
370        self.assertEqual(payment.amount_auth, 180.0)
371        self.assertEqual(payment.p_item, u'')
372        self.assertEqual(error, None)
373
374        error, payment = utils.setPaymentDetails('bed_allocation',self.student)
375        self.assertEqual(payment.p_level, 100)
376        self.assertEqual(payment.p_session, 2004)
377        self.assertEqual(payment.amount_auth, 150.0)
378        self.assertEqual(payment.p_item, u'')
379        self.assertEqual(error, None)
380
381        error, payment = utils.setPaymentDetails('transfer',self.student)
382        self.assertEqual(payment.p_level, 100)
383        self.assertEqual(payment.p_session, 2004)
384        self.assertEqual(payment.amount_auth, 90.0)
385        self.assertEqual(payment.p_item, u'')
386        self.assertEqual(error, None)
387        return
Note: See TracBrowser for help on using the repository browser.