source: main/waeup.aaue/trunk/src/waeup/aaue/students/tests/test_browser.py @ 12983

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

Activate Late Registration Fee payments.

  • Property svn:keywords set to Id
File size: 17.7 KB
Line 
1## $Id: test_browser.py 12504 2015-01-21 12:44:54Z 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
21import grok
22from mechanize import LinkNotFoundError
23from hurry.workflow.interfaces import IWorkflowState
24from zope.component.hooks import setSite, clearSite
25from zope.component import getUtility, createObject
26from waeup.kofa.app import University
27from waeup.kofa.students.tests.test_browser import StudentsFullSetup
28from waeup.kofa.students.accommodation import BedTicket
29from waeup.kofa.testing import FunctionalTestCase
30from waeup.kofa.browser.tests.test_pdf import samples_dir
31from waeup.aaue.testing import FunctionalLayer
32
33
34class StudentProcessorTest(FunctionalTestCase):
35    """Perform some batching tests.
36    """
37
38    layer = FunctionalLayer
39
40    def setUp(self):
41        super(StudentProcessorTest, self).setUp()
42        # Setup a sample site for each test
43        app = University()
44        self.dc_root = tempfile.mkdtemp()
45        app['datacenter'].setStoragePath(self.dc_root)
46
47        # Prepopulate the ZODB...
48        self.getRootFolder()['app'] = app
49        # we add the site immediately after creation to the
50        # ZODB. Catalogs and other local utilities are not setup
51        # before that step.
52        self.app = self.getRootFolder()['app']
53        # Set site here. Some of the following setup code might need
54        # to access grok.getSite() and should get our new app then
55        setSite(app)
56
57
58    def tearDown(self):
59        super(StudentProcessorTest, self).tearDown()
60        shutil.rmtree(self.workdir)
61        shutil.rmtree(self.dc_root)
62        clearSite()
63        return
64
65class OfficerUITests(StudentsFullSetup):
66    # Tests for Student class views and pages
67
68    layer = FunctionalLayer
69
70    def test_gpa_calculation(self):
71        studylevel = createObject(u'waeup.StudentStudyLevel')
72        studylevel.level = 100
73        studylevel.level_session = 2005
74        self.student['studycourse'].entry_mode = 'ug_ft'
75        self.student['studycourse'].addStudentStudyLevel(
76            self.certificate, studylevel)
77        # First course has been added automatically.
78        # Set score.
79        studylevel['COURSE1'].score = 55
80        # GPA is 3.0.
81        self.assertEqual(studylevel.gpa_params[0], 3.0)
82        courseticket = createObject('waeup.CourseTicket')
83        courseticket.code = 'ANYCODE'
84        courseticket.title = u'Any TITLE'
85        courseticket.credits = 13
86        courseticket.score = 66
87        courseticket.semester = 1
88        courseticket.dcode = u'ANYDCODE'
89        courseticket.fcode = u'ANYFCODE'
90        studylevel['COURSE2'] = courseticket
91        # total credits
92        self.assertEqual(self.student['studycourse']['100'].gpa_params[1], 23)
93        # weigheted credits = 3 * 10 + 4 * 13
94        self.assertEqual(self.student['studycourse']['100'].gpa_params[2], 82.0)
95        # sgpa = 82 / 23
96        self.assertEqual(self.student['studycourse']['100'].gpa_params[0], 3.565)
97        return
98
99class StudentUITests(StudentsFullSetup):
100    """Tests for customized student class views and pages
101    """
102
103    layer = FunctionalLayer
104
105    def setUp(self):
106        super(StudentUITests, self).setUp()
107
108        bedticket = BedTicket()
109        bedticket.booking_session = 2004
110        bedticket.bed_type = u'any bed type'
111        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
112        bedticket.bed_coordinates = u'My bed coordinates'
113        self.student['accommodation'].addBedTicket(bedticket)
114
115    def test_manage_payments(self):
116        # Add missing configuration data
117        self.app['configuration']['2004'].gown_fee = 150.0
118        self.app['configuration']['2004'].transfer_fee = 90.0
119        self.app['configuration']['2004'].booking_fee = 150.0
120        self.app['configuration']['2004'].maint_fee = 180.0
121        self.app['configuration']['2004'].late_fee = 80.0
122
123        # Managers can add online payment tickets
124        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
125        self.browser.open(self.payments_path)
126        self.browser.getLink("Add current session payment ticket").click()
127        self.browser.getControl(name="form.p_category").value = ['schoolfee']
128        self.browser.getControl("Create ticket").click()
129        self.assertMatches('...Wrong state...',
130                           self.browser.contents)
131        IWorkflowState(self.student).setState('cleared')
132        self.browser.open(self.payments_path + '/addop')
133        self.browser.getControl("Create ticket").click()
134        self.assertMatches('...Amount could not be determined...',
135                           self.browser.contents)
136        self.app['configuration']['2004'].school_fee_1 = 6666.0
137        #self.browser.getControl(name="form.p_category").value = ['schoolfee']
138        # Accepotance fee must be paid first
139        #self.browser.getControl("Create ticket").click()
140        #self.assertMatches('...Please pay acceptance fee first...',
141        #                   self.browser.contents)
142        self.app['configuration']['2004'].clearance_fee = 666.0
143        self.browser.getControl(name="form.p_category").value = ['clearance']
144        self.browser.getControl("Create ticket").click()
145        ctrl = self.browser.getControl(name='val_id')
146        cpt_value = ctrl.options[0]
147        # School fee payment ticket can be added ...
148        self.browser.open(self.payments_path + '/addop')
149        self.browser.getControl(name="form.p_category").value = ['schoolfee']
150        self.browser.getControl("Create ticket").click()
151        self.assertMatches('...ticket created...',
152                           self.browser.contents)
153        # ... but not paid through the query_history page.
154        ctrl = self.browser.getControl(name='val_id')
155        sfpt_value = ctrl.options[1]
156        self.student['studycourse'].entry_session = 2013
157        self.browser.open(self.payments_path + '/' + sfpt_value)
158        self.browser.getLink("Query eTranzact History").click()
159        self.assertMatches('...alert-danger">Please pay acceptance fee first...',
160                           self.browser.contents)
161        # If clearance/acceptance fee is paid ...
162        self.student['payments'][cpt_value].approveStudentPayment()
163        self.browser.getLink("Query eTranzact History").click()
164        # ... query_history page is accessible.
165        self.assertMatches(
166            '...<h1 class="kofa-content-label">Requery eTranzact History</h1>...',
167            self.browser.contents)
168        # Managers can open school fee payment slip
169        self.browser.open(self.payments_path + '/' + sfpt_value)
170        self.browser.getLink("Download payment slip").click()
171        self.assertEqual(self.browser.headers['Status'], '200 Ok')
172        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
173        # If school fee ticket is paid ...
174        ticket = self.student['payments'][sfpt_value].approveStudentPayment()
175        # ... no further school fee ticket can be added.
176        self.browser.open(self.payments_path + '/addop')
177        self.browser.getControl(name="form.p_category").value = ['schoolfee']
178        self.browser.getControl("Create ticket").click()
179        self.assertMatches('...This type of payment has already been made...',
180                           self.browser.contents)
181        self.browser.open(self.payments_path + '/addop')
182        self.browser.getControl(name="form.p_category").value = ['late_registration']
183        self.browser.getControl("Create ticket").click()
184        self.assertMatches('...ticket created...',
185                           self.browser.contents)
186
187    def deactivated_test_for_instalment_payments(self):
188        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
189        self.browser.open(self.payments_path)
190        self.browser.open(self.payments_path + '/addop')
191        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
192        self.browser.getControl("Create ticket").click()
193        self.assertMatches('...ticket created...',
194                           self.browser.contents)
195        # We can't add the 2nd instalment ticket because the
196        # first one has not yet been approved.
197        self.browser.open(self.payments_path + '/addop')
198        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
199        self.browser.getControl("Create ticket").click()
200        self.assertMatches('...1st school fee instalment has not yet been paid...',
201                           self.browser.contents)
202        # Ok, then we approve the first instalment ...
203        self.browser.open(self.payments_path)
204        ctrl = self.browser.getControl(name='val_id')
205        p_id = ctrl.options[0]
206        self.browser.open(self.payments_path + '/' + p_id + '/approve')
207        # ... add the second instalment ...
208        self.browser.open(self.payments_path + '/addop')
209        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
210        self.browser.getControl("Create ticket").click()
211        self.assertMatches('...ticket created...',
212                           self.browser.contents)
213        # ... approve the second instalment ...
214        ctrl = self.browser.getControl(name='val_id')
215        p_id = ctrl.options[1]
216        self.browser.open(self.payments_path + '/' + p_id + '/approve')
217        # ... and finally add the 1st instalment for the next session
218        # provided that student is returning.
219        IWorkflowState(self.student).setState('returning')
220        self.browser.open(self.payments_path + '/addop')
221        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
222        self.browser.getControl("Create ticket").click()
223        self.assertMatches('...Session configuration object is not...',
224                           self.browser.contents)
225        # Uups, we forgot to add a session configuration for next session
226        configuration = createObject('waeup.SessionConfiguration')
227        configuration.academic_session = 2005
228        self.app['configuration'].addSessionConfiguration(configuration)
229        self.app['configuration']['2005'].school_base = 7777.0
230        self.browser.open(self.payments_path + '/addop')
231        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
232        self.browser.getControl("Create ticket").click()
233        self.assertMatches('...ticket created...',
234                           self.browser.contents)
235        # If the session configuration doesn't exist an error message will
236        # be shown. No other requirement is being checked.
237        del self.app['configuration']['2004']
238        self.browser.open(self.payments_path)
239        self.browser.getLink("Add current session payment ticket").click()
240        self.browser.getControl("Create ticket").click()
241        self.assertMatches('...Session configuration object is not...',
242                           self.browser.contents)
243
244    def test_student_payments(self):
245        # Login
246        IWorkflowState(self.student).setState('returning')
247        self.browser.open(self.login_path)
248        self.browser.getControl(name="form.login").value = self.student_id
249        self.browser.getControl(name="form.password").value = 'spwd'
250        self.browser.getControl("Login").click()
251        self.browser.open(self.student_path + '/payments')
252        self.assertTrue(
253          'Add current session payment ticket' in self.browser.contents)
254        self.assertFalse(
255          'Add previous session payment ticket' in self.browser.contents)
256        return
257
258    def deactivated_test_student_course_registration(self):
259
260        # Add more courses
261        self.course2 = createObject('waeup.Course')
262        self.course2.code = 'COURSE2'
263        self.course2.semester = 2
264        self.course2.credits = 10
265        self.course2.passmark = 40
266        self.app['faculties']['fac1']['dep1'].courses.addCourse(
267            self.course2)
268        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
269            self.course2, level=100)
270        self.course3 = createObject('waeup.Course')
271        self.course3.code = 'COURSE3'
272        self.course3.semester = 3
273        self.course3.credits = 10
274        self.course3.passmark = 40
275        self.app['faculties']['fac1']['dep1'].courses.addCourse(
276            self.course3)
277        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
278            self.course3, level=100)
279
280        # Login as student
281        self.browser.open(self.login_path)
282        IWorkflowState(self.student).setState('school fee paid')
283        self.browser.open(self.login_path)
284        self.browser.getControl(name="form.login").value = self.student_id
285        self.browser.getControl(name="form.password").value = 'spwd'
286        self.browser.getControl("Login").click()
287        # Students can add the current study level
288        self.browser.getLink("Study Course").click()
289        self.browser.getLink("Add course list").click()
290        self.assertMatches('...Add current level 100 (Year 1)...',
291                           self.browser.contents)
292        self.browser.getControl("Create course list now").click()
293        # Student has not paid second instalment, therefore a level
294        # with two course ticket was created (semester 1 and combined)
295        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
296        self.browser.getLink("100").click()
297        self.browser.getLink("Edit course list").click()
298        self.browser.getControl("Add course ticket").click()
299        # Student can't add second semester course
300        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
301        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
302        self.assertFalse('<option value="COURSE2">' in self.browser.contents)
303
304        # Let's remove level and see what happens after 2nd instalment payment
305        del(self.student['studycourse']['100'])
306        payment2 = createObject('waeup.StudentOnlinePayment')
307        payment2.p_category = u'schoolfee_2'
308        payment2.p_session = self.student.current_session
309        self.student['payments']['anykey'] = payment2
310        self.browser.open(self.studycourse_path)
311        self.browser.getLink("Add course list").click()
312        self.browser.getControl("Create course list now").click()
313        # Still only 2 tickets have been created since payment ticket
314        # was not paid
315        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
316        payment2.p_state = u'paid'
317        del(self.student['studycourse']['100'])
318        self.browser.open(self.studycourse_path)
319        self.browser.getLink("Add course list").click()
320        self.browser.getControl("Create course list now").click()
321        # Now 2nd semester course has been added
322        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
323        # Student can add second semester course
324        self.browser.getLink("100").click()
325        self.browser.getLink("Edit course list").click()
326        self.browser.getControl("Add course ticket").click()
327        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
328        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
329        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
330        return
331
332    def test_set_matric_number(self):
333        # Login as student
334        self.browser.open(self.login_path)
335        IWorkflowState(self.student).setState('school fee paid')
336        self.browser.open(self.login_path)
337        self.browser.getControl(name="form.login").value = self.student_id
338        self.browser.getControl(name="form.password").value = 'spwd'
339        self.browser.getControl("Login").click()
340        self.assertRaises(
341            LinkNotFoundError,
342            self.browser.getLink, 'Get Matriculation Number')
343        self.student.matric_number = None
344        site = grok.getSite()
345        site['configuration'].next_matric_integer = 1
346        self.student['studycourse'].certificate.study_mode = 'ug_pt'
347        self.browser.open(self.student_path)
348        self.assertRaises(
349            LinkNotFoundError,
350            self.browser.getLink, 'Download matriculation number slip')
351        self.browser.getLink("Get Matriculation Number").click()
352        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
353            in self.browser.contents)
354        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
355        self.assertRaises(
356            LinkNotFoundError,
357            self.browser.getLink, 'Get Matriculation Number')
358        # Setting matric number is logged.
359        logfile = os.path.join(
360            self.app['datacenter'].storage, 'logs', 'students.log')
361        logcontent = open(logfile).read()
362        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
363                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
364        # Matric Number Slip can be downloaded
365        self.browser.getLink("Download matriculation number slip").click()
366        self.assertEqual(self.browser.headers['Status'], '200 Ok')
367        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
368        path = os.path.join(samples_dir(), 'transcript.pdf')
369        open(path, 'wb').write(self.browser.contents)
370        print "Sample PDF matric_number_slip.pdf written to %s" % path
371        return
372
Note: See TracBrowser for help on using the repository browser.