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

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

Students can open the customized pdf course registration slip only if they
have registered their course list.

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