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

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

Enable postgraduate workflow in custom package.

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