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

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

Student are always allowed to download course registration slips of passed sessions.

  • Property svn:keywords set to Id
File size: 22.0 KB
Line 
1## $Id: test_browser.py 13051 2015-06-15 15:04:19Z 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, the student is automatically set to
176        # school fee paid...
177        ticket = self.student['payments'][sfpt_value].approveStudentPayment()
178        self.assertEqual(self.student.state, 'school fee paid')
179        # ... no further school fee ticket can be added.
180        self.browser.open(self.payments_path + '/addop')
181        self.browser.getControl(name="form.p_category").value = ['schoolfee']
182        self.browser.getControl("Create ticket").click()
183        self.assertMatches('...Wrong state...',
184                           self.browser.contents)
185        self.browser.open(self.payments_path + '/addop')
186        self.browser.getControl(name="form.p_category").value = ['late_registration']
187        self.browser.getControl("Create ticket").click()
188        self.assertMatches('...ticket created...',
189                           self.browser.contents)
190
191    def deactivated_test_for_instalment_payments(self):
192        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
193        self.browser.open(self.payments_path)
194        self.browser.open(self.payments_path + '/addop')
195        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
196        self.browser.getControl("Create ticket").click()
197        self.assertMatches('...ticket created...',
198                           self.browser.contents)
199        # We can't add the 2nd instalment ticket because the
200        # first one has not yet been approved.
201        self.browser.open(self.payments_path + '/addop')
202        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
203        self.browser.getControl("Create ticket").click()
204        self.assertMatches('...1st school fee instalment has not yet been paid...',
205                           self.browser.contents)
206        # Ok, then we approve the first instalment ...
207        self.browser.open(self.payments_path)
208        ctrl = self.browser.getControl(name='val_id')
209        p_id = ctrl.options[0]
210        self.browser.open(self.payments_path + '/' + p_id + '/approve')
211        # ... add the second instalment ...
212        self.browser.open(self.payments_path + '/addop')
213        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
214        self.browser.getControl("Create ticket").click()
215        self.assertMatches('...ticket created...',
216                           self.browser.contents)
217        # ... approve the second instalment ...
218        ctrl = self.browser.getControl(name='val_id')
219        p_id = ctrl.options[1]
220        self.browser.open(self.payments_path + '/' + p_id + '/approve')
221        # ... and finally add the 1st instalment for the next session
222        # provided that student is returning.
223        IWorkflowState(self.student).setState('returning')
224        self.browser.open(self.payments_path + '/addop')
225        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
226        self.browser.getControl("Create ticket").click()
227        self.assertMatches('...Session configuration object is not...',
228                           self.browser.contents)
229        # Uups, we forgot to add a session configuration for next session
230        configuration = createObject('waeup.SessionConfiguration')
231        configuration.academic_session = 2005
232        self.app['configuration'].addSessionConfiguration(configuration)
233        self.app['configuration']['2005'].school_base = 7777.0
234        self.browser.open(self.payments_path + '/addop')
235        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
236        self.browser.getControl("Create ticket").click()
237        self.assertMatches('...ticket created...',
238                           self.browser.contents)
239        # If the session configuration doesn't exist an error message will
240        # be shown. No other requirement is being checked.
241        del self.app['configuration']['2004']
242        self.browser.open(self.payments_path)
243        self.browser.getLink("Add current session payment ticket").click()
244        self.browser.getControl("Create ticket").click()
245        self.assertMatches('...Session configuration object is not...',
246                           self.browser.contents)
247
248    def test_student_payments(self):
249        # Login
250        IWorkflowState(self.student).setState('returning')
251        self.browser.open(self.login_path)
252        self.browser.getControl(name="form.login").value = self.student_id
253        self.browser.getControl(name="form.password").value = 'spwd'
254        self.browser.getControl("Login").click()
255        self.browser.open(self.student_path + '/payments')
256        self.assertTrue(
257          'Add current session payment ticket' in self.browser.contents)
258        self.assertFalse(
259          'Add previous session payment ticket' in self.browser.contents)
260        return
261
262    def test_late_registration(self):
263        # Login
264        delta = timedelta(days=10)
265        self.app['configuration'][
266            '2004'].coursereg_deadline = datetime.now(pytz.utc) - delta
267        IWorkflowState(self.student).setState('school fee paid')
268        # Current session is 2004. Here we test course registration for
269        # returning students.
270        self.student['studycourse'].entry_session = 2003
271        self.browser.open(self.login_path)
272        self.browser.getControl(name="form.login").value = self.student_id
273        self.browser.getControl(name="form.password").value = 'spwd'
274        self.browser.getControl("Login").click()
275        self.browser.open(self.payments_path)
276        self.browser.open(self.payments_path + '/addop')
277        self.browser.getControl(name="form.p_category").value = ['late_registration']
278        self.browser.getControl("Create ticket").click()
279        self.assertMatches('...ticket created...',
280                           self.browser.contents)
281        self.browser.open(self.payments_path)
282        ctrl = self.browser.getControl(name='val_id')
283        value = ctrl.options[0]
284        self.browser.getLink("Study Course").click()
285        self.browser.getLink("Add course list").click()
286        self.assertMatches('...Add current level 100 (Year 1)...',
287                           self.browser.contents)
288        self.browser.getControl("Create course list now").click()
289        self.browser.getLink("100").click()
290        self.browser.getLink("Edit course list").click()
291        self.browser.getControl("Register course list").click()
292        self.assertTrue('Course registration has ended. Please pay' in self.browser.contents)
293        self.student['payments'][value].approve()
294        self.browser.getControl("Register course list").click()
295        self.assertTrue('Course list has been registered' in self.browser.contents)
296        self.assertEqual(self.student.state, 'courses registered')
297        # Reset student and check if fresh students are always allowed to
298        # register courses.
299        self.student['studycourse'].entry_session = 2004
300        del self.student['payments'][value]
301        IWorkflowState(self.student).setState('school fee paid')
302        self.browser.open(self.studycourse_path + '/100/edit')
303        self.browser.getControl("Register course list").click()
304        self.assertTrue('Course list has been registered' in self.browser.contents)
305        return
306
307
308    def deactivated_test_student_course_registration(self):
309        # Add more courses
310        self.course2 = createObject('waeup.Course')
311        self.course2.code = 'COURSE2'
312        self.course2.semester = 2
313        self.course2.credits = 10
314        self.course2.passmark = 40
315        self.app['faculties']['fac1']['dep1'].courses.addCourse(
316            self.course2)
317        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
318            self.course2, level=100)
319        self.course3 = createObject('waeup.Course')
320        self.course3.code = 'COURSE3'
321        self.course3.semester = 3
322        self.course3.credits = 10
323        self.course3.passmark = 40
324        self.app['faculties']['fac1']['dep1'].courses.addCourse(
325            self.course3)
326        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
327            self.course3, level=100)
328
329        # Login as student
330        self.browser.open(self.login_path)
331        IWorkflowState(self.student).setState('school fee paid')
332        self.browser.open(self.login_path)
333        self.browser.getControl(name="form.login").value = self.student_id
334        self.browser.getControl(name="form.password").value = 'spwd'
335        self.browser.getControl("Login").click()
336        # Students can add the current study level
337        self.browser.getLink("Study Course").click()
338        self.browser.getLink("Add course list").click()
339        self.assertMatches('...Add current level 100 (Year 1)...',
340                           self.browser.contents)
341        self.browser.getControl("Create course list now").click()
342        # Student has not paid second instalment, therefore a level
343        # with two course ticket was created (semester 1 and combined)
344        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
345        self.browser.getLink("100").click()
346        self.browser.getLink("Edit course list").click()
347        self.browser.getControl("Add course ticket").click()
348        # Student can't add second semester course
349        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
350        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
351        self.assertFalse('<option value="COURSE2">' in self.browser.contents)
352
353        # Let's remove level and see what happens after 2nd instalment payment
354        del(self.student['studycourse']['100'])
355        payment2 = createObject('waeup.StudentOnlinePayment')
356        payment2.p_category = u'schoolfee_2'
357        payment2.p_session = self.student.current_session
358        self.student['payments']['anykey'] = payment2
359        self.browser.open(self.studycourse_path)
360        self.browser.getLink("Add course list").click()
361        self.browser.getControl("Create course list now").click()
362        # Still only 2 tickets have been created since payment ticket
363        # was not paid
364        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
365        payment2.p_state = u'paid'
366        del(self.student['studycourse']['100'])
367        self.browser.open(self.studycourse_path)
368        self.browser.getLink("Add course list").click()
369        self.browser.getControl("Create course list now").click()
370        # Now 2nd semester course has been added
371        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
372        # Student can add second semester course
373        self.browser.getLink("100").click()
374        self.browser.getLink("Edit course list").click()
375        self.browser.getControl("Add course ticket").click()
376        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
377        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
378        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
379        return
380
381    def test_set_matric_number(self):
382        # Login as student
383        self.browser.open(self.login_path)
384        IWorkflowState(self.student).setState('school fee paid')
385        self.browser.open(self.login_path)
386        self.browser.getControl(name="form.login").value = self.student_id
387        self.browser.getControl(name="form.password").value = 'spwd'
388        self.browser.getControl("Login").click()
389        self.assertRaises(
390            LinkNotFoundError,
391            self.browser.getLink, 'Get Matriculation Number')
392        self.student.matric_number = None
393        site = grok.getSite()
394        site['configuration'].next_matric_integer = 1
395        self.student['studycourse'].certificate.study_mode = 'ug_pt'
396        self.browser.open(self.student_path)
397        self.assertRaises(
398            LinkNotFoundError,
399            self.browser.getLink, 'Download matriculation number slip')
400        self.browser.getLink("Get Matriculation Number").click()
401        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
402            in self.browser.contents)
403        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
404        self.assertRaises(
405            LinkNotFoundError,
406            self.browser.getLink, 'Get Matriculation Number')
407        # Setting matric number is logged.
408        logfile = os.path.join(
409            self.app['datacenter'].storage, 'logs', 'students.log')
410        logcontent = open(logfile).read()
411        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
412                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
413        # Matric Number Slip can be downloaded
414        self.browser.getLink("Download matriculation number slip").click()
415        self.assertEqual(self.browser.headers['Status'], '200 Ok')
416        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
417        path = os.path.join(samples_dir(), 'transcript.pdf')
418        open(path, 'wb').write(self.browser.contents)
419        print "Sample PDF matric_number_slip.pdf written to %s" % path
420        return
421
422    def test_student_course_registration(self):
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't open the customized pdf course registration slip
435        self.browser.open(
436            self.student_path + '/studycourse/100/course_registration_slip.pdf')
437        self.assertTrue('Forbidden' in self.browser.contents)
438        # They can open slips from the previous session ...
439        self.student['studycourse'].current_level = 200
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')
444        # or if they have registered their course list
445        self.student['studycourse'].current_level = 200
446        IWorkflowState(self.student).setState('courses registered')
447        self.browser.open(self.student_path + '/studycourse/100')
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'], 'application/pdf')
Note: See TracBrowser for help on using the repository browser.