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

Last change on this file since 14041 was 14000, checked in by Henrik Bettermann, 8 years ago

Show course results only if students are returning or current level is different from course level.

  • Property svn:keywords set to Id
File size: 40.0 KB
Line 
1## $Id: test_browser.py 14000 2016-06-30 09:23: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 StringIO import StringIO
24from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
25from zope.securitypolicy.interfaces import IPrincipalRoleManager
26from datetime import datetime, timedelta, date
27from mechanize import LinkNotFoundError
28from hurry.workflow.interfaces import IWorkflowState
29from zope.event import notify
30from zope.component.hooks import setSite, clearSite
31from zope.component import getUtility, createObject, queryUtility
32from zope.catalog.interfaces import ICatalog
33from waeup.kofa.app import University
34from waeup.kofa.interfaces import VALIDATED
35from waeup.kofa.students.tests.test_browser import StudentsFullSetup
36from waeup.kofa.students.accommodation import BedTicket
37from waeup.kofa.testing import FunctionalTestCase
38from waeup.kofa.authentication import LocalRoleSetEvent
39from waeup.kofa.browser.tests.test_pdf import samples_dir
40from waeup.aaue.testing import FunctionalLayer
41
42SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
43
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
69    def tearDown(self):
70        super(StudentProcessorTest, self).tearDown()
71        shutil.rmtree(self.workdir)
72        shutil.rmtree(self.dc_root)
73        clearSite()
74        return
75
76UPLOAD_CSV_TEMPLATE = (
77    'matric_number,student_id,display_fullname,level,code,level_session,'
78    'score,ca\r\n'
79    '234,E1000000,Anna Tester,100,COURSE1,2004,%s,%s\r\n')
80
81class OfficerUITests(StudentsFullSetup):
82    # Tests for Student class views and pages
83
84    layer = FunctionalLayer
85
86    def login_as_lecturer(self):
87        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
88        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
89        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
90        # Add course ticket
91        studylevel = createObject(u'waeup.StudentStudyLevel')
92        studylevel.level = 100
93        studylevel.level_session = 2004
94        self.student['studycourse'].addStudentStudyLevel(
95            self.certificate, studylevel)
96        # Assign local Lecturer role for a certificate.
97        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
98        prmlocal = IPrincipalRoleManager(course)
99        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
100        notify(LocalRoleSetEvent(
101            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
102        # Login as lecturer.
103        self.browser.open(self.login_path)
104        self.browser.getControl(name="form.login").value = 'mrslecturer'
105        self.browser.getControl(
106            name="form.password").value = 'mrslecturersecret'
107        self.browser.getControl("Login").click()
108        # Store reused urls/paths
109        self.course_url = (
110            'http://localhost/app/faculties/fac1/dep1/courses/COURSE1')
111        self.edit_scores_url = '%s/edit_scores' % self.course_url
112        # Set standard parameters
113        self.app['configuration'].current_academic_session = 2004
114        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
115        IWorkflowState(self.student).setState(VALIDATED)
116
117
118    def test_gpa_calculation(self):
119        studylevel = createObject(u'waeup.StudentStudyLevel')
120        studylevel.level = 100
121        studylevel.level_session = 2005
122        self.student['studycourse'].entry_mode = 'ug_ft'
123        self.student['studycourse'].addStudentStudyLevel(
124            self.certificate, studylevel)
125        # First course has been added automatically.
126        # Set score.
127        studylevel['COURSE1'].score = 35
128        studylevel['COURSE1'].ca = 20
129        # GPA is 3.0.
130        self.assertEqual(studylevel.gpa_params[0], 3.0)
131        courseticket = createObject('waeup.CourseTicket')
132        courseticket.code = 'ANYCODE'
133        courseticket.title = u'Any TITLE'
134        courseticket.credits = 13
135        courseticket.score = 44
136        courseticket.ca = 22
137        courseticket.semester = 1
138        courseticket.dcode = u'ANYDCODE'
139        courseticket.fcode = u'ANYFCODE'
140        studylevel['COURSE2'] = courseticket
141        # total credits
142        self.assertEqual(self.student['studycourse']['100'].gpa_params[1], 23)
143        # weigheted credits = 3 * 10 + 4 * 13
144        self.assertEqual(self.student['studycourse']['100'].gpa_params[2], 82.0)
145        # sgpa = 82 / 23
146        self.assertEqual(self.student['studycourse']['100'].gpa_params[0], 3.565)
147        return
148
149    def test_manage_payments(self):
150        # Add missing configuration data
151        self.app['configuration']['2004'].gown_fee = 150.0
152        self.app['configuration']['2004'].transfer_fee = 90.0
153        self.app['configuration']['2004'].booking_fee = 150.0
154        self.app['configuration']['2004'].maint_fee = 180.0
155        self.app['configuration']['2004'].late_fee = 80.0
156
157        # Managers can add online payment tickets
158        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
159        self.browser.open(self.payments_path)
160        self.browser.getLink("Add current session payment ticket").click()
161        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
162        self.browser.getControl("Create ticket").click()
163        self.assertMatches('...Wrong state...',
164                           self.browser.contents)
165        IWorkflowState(self.student).setState('cleared')
166        self.browser.open(self.payments_path + '/addop')
167        self.browser.getControl("Create ticket").click()
168        self.assertMatches('...Amount could not be determined...',
169                           self.browser.contents)
170        #self.browser.getControl(name="form.p_category").value = ['schoolfee']
171        # Accepotance fee must be paid first
172        #self.browser.getControl("Create ticket").click()
173        #self.assertMatches('...Please pay acceptance fee first...',
174        #                   self.browser.contents)
175        self.app['configuration']['2004'].clearance_fee = 666.0
176        self.browser.getControl(name="form.p_category").value = ['clearance_incl']
177        self.browser.getControl("Create ticket").click()
178        ctrl = self.browser.getControl(name='val_id')
179        cpt_value = ctrl.options[0]
180        # School fee payment ticket can be added ...
181        self.student['studycourse'].certificate.school_fee_1 = 6666.0
182        self.student.nationality = u'NG'
183        self.browser.open(self.payments_path + '/addop')
184        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
185        self.browser.getControl("Create ticket").click()
186        self.assertMatches('...ticket created...',
187                           self.browser.contents)
188        # ... but not paid through the query_history page.
189        ctrl = self.browser.getControl(name='val_id')
190        sfpt_value = ctrl.options[1]
191        self.student['studycourse'].entry_session = 2013
192        self.browser.open(self.payments_path + '/' + sfpt_value)
193        self.browser.getLink("Query eTranzact History").click()
194        self.assertMatches('...alert-danger">Please pay acceptance fee first...',
195                           self.browser.contents)
196        # If clearance/acceptance fee is paid ...
197        self.student['payments'][cpt_value].approveStudentPayment()
198        self.browser.getLink("Query eTranzact History").click()
199        # ... query_history page is accessible.
200        self.assertMatches(
201            '...<h1 class="kofa-content-label">Requery eTranzact History</h1>...',
202            self.browser.contents)
203        # Managers can open school fee payment slip
204        self.browser.open(self.payments_path + '/' + sfpt_value)
205        self.browser.getLink("Download payment slip").click()
206        self.assertEqual(self.browser.headers['Status'], '200 Ok')
207        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
208        # If school fee ticket is paid, the student is automatically set to
209        # school fee paid...
210        ticket = self.student['payments'][sfpt_value].approveStudentPayment()
211        self.assertEqual(self.student.state, 'school fee paid')
212        # ... no further school fee ticket can be added.
213        self.browser.open(self.payments_path + '/addop')
214        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
215        self.browser.getControl("Create ticket").click()
216        self.assertMatches('...Wrong state...',
217                           self.browser.contents)
218        self.browser.open(self.payments_path + '/addop')
219        self.browser.getControl(name="form.p_category").value = ['late_registration']
220        self.browser.getControl("Create ticket").click()
221        self.assertMatches('...ticket created...',
222                           self.browser.contents)
223        return
224
225    def test_for_instalment_payments(self):
226        self.student['studycourse'].certificate.study_mode = 'ug_pt'
227        self.student['studycourse'].certificate.school_fee_1 = 6666.0
228        self.app['configuration']['2004'].union_fee = 1250.0
229        self.app['configuration']['2004'].welfare_fee = 750.0
230        self.student.nationality = u'NG'
231        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
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.assertTrue(
236            'Part-time students are not allowed' in self.browser.contents)
237        self.student['studycourse'].certificate.study_mode = 'ug_ft'
238        self.browser.open(self.payments_path + '/addop')
239        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
240        self.browser.getControl("Create ticket").click()
241        self.assertTrue(
242            'Wrong state. Only students in state \'cleared\' are allowed to pay by instalments'
243            in self.browser.contents)
244        IWorkflowState(self.student).setState('cleared')
245        self.browser.open(self.payments_path + '/addop')
246        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
247        self.browser.getControl("Create ticket").click()
248        self.assertTrue('ticket created' in self.browser.contents)
249        # We can't add the 2nd instalment ticket because the
250        # first one has not yet been approved.
251        #self.browser.open(self.payments_path + '/addop')
252        #self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
253        #self.browser.getControl("Create ticket").click()
254        #self.assertMatches('...1st school fee instalment has not yet been paid...',
255        #                   self.browser.contents)
256        # Ok, then we approve the first instalment ...
257        self.browser.open(self.payments_path)
258        ctrl = self.browser.getControl(name='val_id')
259        p_id = ctrl.options[0]
260        self.browser.open(self.payments_path + '/' + p_id + '/approve')
261        # ... add the second instalment ...
262        self.browser.open(self.payments_path + '/addop')
263        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
264        self.browser.getControl("Create ticket").click()
265        self.assertTrue('ticket created' in self.browser.contents)
266        # ... approve the second instalment ...
267        ctrl = self.browser.getControl(name='val_id')
268        p_id = ctrl.options[1]
269        self.browser.open(self.payments_path + '/' + p_id + '/approve')
270        self.assertEqual(self.student['payments'].values()[0].p_category, 'schoolfee_1')
271        self.assertEqual(self.student['payments'].values()[1].p_category, 'schoolfee_2')
272        # (6666-250)/2 + 1250 + 750 - 500 + 250
273        self.assertEqual(self.student['payments'].values()[0].amount_auth, 4958.0)
274        # (6666-250)/2 + 250
275        self.assertEqual(self.student['payments'].values()[1].amount_auth, 3458.0)
276        return
277
278    def test_manage_payments_bypass_ac_creation(self):
279        self.student['studycourse'].certificate.school_fee_1 = 6666.0
280        self.student.nationality = u'NG'
281        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
282        self.browser.open(self.payments_path)
283        IWorkflowState(self.student).setState('cleared')
284        self.browser.getLink("Add current session payment ticket").click()
285        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
286        self.browser.getControl("Create ticket").click()
287        ctrl = self.browser.getControl(name='val_id')
288        value = ctrl.options[0]
289        self.browser.getLink(value).click()
290        payment_url = self.browser.url
291        logfile = os.path.join(
292            self.app['datacenter'].storage, 'logs', 'students.log')
293        # The ticket can be found in the payments_catalog
294        cat = queryUtility(ICatalog, name='payments_catalog')
295        results = list(cat.searchResults(p_state=('unpaid', 'unpaid')))
296        self.assertTrue(len(results), 1)
297        self.assertTrue(results[0] is self.student['payments'][value])
298        # Managers can approve the payment
299        self.browser.open(payment_url)
300        self.browser.getLink("Approve payment").click()
301        self.assertMatches('...Payment approved...',
302                          self.browser.contents)
303        # Approval is logged in students.log ...
304        logcontent = open(logfile).read()
305        self.assertTrue(
306            'zope.mgr - students.browser.OnlinePaymentApproveView '
307            '- E1000000 - schoolfee_incl payment approved'
308            in logcontent)
309        # ... and in payments.log
310        logfile = os.path.join(
311            self.app['datacenter'].storage, 'logs', 'payments.log')
312        logcontent = open(logfile).read()
313        self.assertTrue(
314            '"zope.mgr",E1000000,%s,schoolfee_incl,6666.0,AP,,,,,,\n' % value
315            in logcontent)
316        # Student is in state school fee paid, no activation
317        # code was necessary.
318        self.assertEqual(self.student.state, 'school fee paid')
319        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
320        return
321
322    def test_scores_csv_upload_available(self):
323        # lecturers can upload a CSV file to set values.
324        self.login_as_lecturer()
325        # set value to change from
326        self.student['studycourse']['100']['COURSE1'].score = 55
327        self.browser.open(self.edit_scores_url)
328        upload_ctrl = self.browser.getControl(name='uploadfile:file')
329        upload_file = StringIO(UPLOAD_CSV_TEMPLATE % ('65','77'))
330        upload_ctrl.add_file(upload_file, 'text/csv', 'myscores.csv')
331        self.browser.getControl("Update editable scores from").click()
332        # value changed
333        self.assertEqual(
334            self.student['studycourse']['100']['COURSE1'].score, 65)
335        self.assertEqual(
336            self.student['studycourse']['100']['COURSE1'].ca, 77)
337
338    def test_lecturers_can_download_course_tickets(self):
339        # A course ticket slip can be downloaded
340        self.login_as_lecturer()
341        pdf_url = '%s/coursetickets.pdf' % self.course_url
342        self.browser.open(pdf_url)
343        self.assertEqual(self.browser.headers['Status'], '200 Ok')
344        self.assertEqual(
345            self.browser.headers['Content-Type'], 'application/pdf')
346        path = os.path.join(samples_dir(), 'coursetickets.pdf')
347        open(path, 'wb').write(self.browser.contents)
348        print "Sample PDF coursetickets.pdf written to %s" % path
349
350class StudentUITests(StudentsFullSetup):
351    """Tests for customized student class views and pages
352    """
353
354    layer = FunctionalLayer
355
356    def setUp(self):
357        super(StudentUITests, self).setUp()
358
359        bedticket = BedTicket()
360        bedticket.booking_session = 2004
361        bedticket.bed_type = u'any bed type'
362        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
363        bedticket.bed_coordinates = u'My bed coordinates'
364        self.student['accommodation'].addBedTicket(bedticket)
365
366    def test_student_payments(self):
367        self.certificate.study_mode = 'ug_ft'
368        self.student['studycourse'].entry_session = 2013
369        self.student['studycourse'].certificate.school_fee_1 = 50250.0
370        self.app['configuration']['2004'].union_fee = 1250.0
371        self.app['configuration']['2004'].welfare_fee = 750.0
372        self.student.nationality = u'NG'
373        # Login
374        IWorkflowState(self.student).setState('cleared')
375        self.browser.open(self.login_path)
376        self.browser.getControl(name="form.login").value = self.student_id
377        self.browser.getControl(name="form.password").value = 'spwd'
378        self.browser.getControl("Login").click()
379        # Test school fee payments
380        self.browser.open(self.student_path + '/payments')
381        self.browser.getLink("Add current session payment ticket").click()
382        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
383        self.browser.getControl("Create ticket").click()
384        self.assertTrue('ticket created' in self.browser.contents)
385        value = self.student['payments'].keys()[0]
386        self.browser.getLink(value).click()
387        self.assertTrue('Amount Authorized' in self.browser.contents)
388        self.assertEqual(self.student['payments'][value].amount_auth, 51750.0)
389        self.browser.open(self.browser.url + '/payment_slip.pdf')
390        self.assertEqual(self.browser.headers['Status'], '200 Ok')
391        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
392        path = os.path.join(samples_dir(), 'payment_slip.pdf')
393        open(path, 'wb').write(self.browser.contents)
394        print "Sample PDF payment_slip.pdf written to %s" % path
395        # Another school fee payment cannot be added
396        self.student['payments'][value].approve()
397        self.browser.open(self.student_path + '/payments')
398        self.browser.getLink("Add current session payment ticket").click()
399        self.browser.getControl(name="form.p_category").value = ['schoolfee']
400        self.browser.getControl("Create ticket").click()
401        self.assertTrue(
402            'You must chose a payment which includes additional fees'
403            in self.browser.contents)
404        #self.assertTrue(
405        #    'Another school fee payment for this session has already been made'
406        #    in self.browser.contents)
407        # Test hostel maintenance payments
408        self.browser.open(self.student_path + '/payments')
409        self.browser.getLink("Add current session payment ticket").click()
410        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
411        self.browser.getControl("Create ticket").click()
412        self.assertTrue('ticket created' in self.browser.contents)
413        value = self.student['payments'].keys()[1]
414        self.browser.getLink(value).click()
415        self.assertTrue('<span>My bed coordinates</span>' in self.browser.contents)
416        self.assertEqual(self.student['payments'][value].amount_auth, 876.0)
417        return
418
419    def test_late_registration(self):
420        # Login
421        delta = timedelta(days=10)
422        self.app['configuration'][
423            '2004'].coursereg_deadline = datetime.now(pytz.utc) - delta
424        IWorkflowState(self.student).setState('school fee paid')
425        # Current session is 2004. Here we test course registration for
426        # returning students.
427        self.student['studycourse'].entry_session = 2003
428        self.browser.open(self.login_path)
429        self.browser.getControl(name="form.login").value = self.student_id
430        self.browser.getControl(name="form.password").value = 'spwd'
431        self.browser.getControl("Login").click()
432        self.browser.open(self.payments_path)
433        self.browser.open(self.payments_path + '/addop')
434        self.browser.getControl(name="form.p_category").value = ['late_registration']
435        self.browser.getControl("Create ticket").click()
436        self.assertMatches('...ticket created...',
437                           self.browser.contents)
438        self.browser.getLink("Study Course").click()
439        self.browser.getLink("Add course list").click()
440        self.assertMatches('...Add current level 100 (Year 1)...',
441                           self.browser.contents)
442        self.browser.getControl("Create course list now").click()
443        self.student['studycourse']['100']['COURSE1'].score = 987
444        self.browser.getLink("100").click()
445        # Course results can't be seen
446        self.assertFalse('987' in self.browser.contents)
447        self.browser.getLink("Edit course list").click()
448        self.assertFalse('987' in self.browser.contents)
449        self.browser.getControl("Register course list").click()
450        self.assertTrue('Course registration has ended. Please pay' in self.browser.contents)
451        self.student['payments'].values()[0].approve()
452        self.browser.getControl("Register course list").click()
453        self.assertTrue('Course list has been registered' in self.browser.contents)
454        self.assertEqual(self.student.state, 'courses registered')
455        # Reset student and check if fresh students are always allowed to
456        # register courses.
457        self.student['studycourse'].entry_session = 2004
458        del self.student['payments'][self.student['payments'].keys()[0]]
459        IWorkflowState(self.student).setState('school fee paid')
460        self.browser.open(self.studycourse_path + '/100/edit')
461        self.browser.getControl("Register course list").click()
462        self.assertTrue('Course list has been registered' in self.browser.contents)
463        return
464
465
466    def deactivated_test_student_course_registration(self):
467        # Add more courses
468        self.course2 = createObject('waeup.Course')
469        self.course2.code = 'COURSE2'
470        self.course2.semester = 2
471        self.course2.credits = 10
472        self.course2.passmark = 40
473        self.app['faculties']['fac1']['dep1'].courses.addCourse(
474            self.course2)
475        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
476            self.course2, level=100)
477        self.course3 = createObject('waeup.Course')
478        self.course3.code = 'COURSE3'
479        self.course3.semester = 3
480        self.course3.credits = 10
481        self.course3.passmark = 40
482        self.app['faculties']['fac1']['dep1'].courses.addCourse(
483            self.course3)
484        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
485            self.course3, level=100)
486
487        # Login as student
488        self.browser.open(self.login_path)
489        IWorkflowState(self.student).setState('school fee paid')
490        self.browser.open(self.login_path)
491        self.browser.getControl(name="form.login").value = self.student_id
492        self.browser.getControl(name="form.password").value = 'spwd'
493        self.browser.getControl("Login").click()
494        # Students can add the current study level
495        self.browser.getLink("Study Course").click()
496        self.browser.getLink("Add course list").click()
497        self.assertMatches('...Add current level 100 (Year 1)...',
498                           self.browser.contents)
499        self.browser.getControl("Create course list now").click()
500        # Student has not paid second instalment, therefore a level
501        # with two course ticket was created (semester 1 and combined)
502        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
503        self.browser.getLink("100").click()
504        self.browser.getLink("Edit course list").click()
505        self.browser.getControl("Add course ticket").click()
506        # Student can't add second semester course
507        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
508        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
509        self.assertFalse('<option value="COURSE2">' in self.browser.contents)
510
511        # Let's remove level and see what happens after 2nd instalment payment
512        del(self.student['studycourse']['100'])
513        payment2 = createObject('waeup.StudentOnlinePayment')
514        payment2.p_category = u'schoolfee_2'
515        payment2.p_session = self.student.current_session
516        self.student['payments']['anykey'] = payment2
517        self.browser.open(self.studycourse_path)
518        self.browser.getLink("Add course list").click()
519        self.browser.getControl("Create course list now").click()
520        # Still only 2 tickets have been created since payment ticket
521        # was not paid
522        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
523        payment2.p_state = u'paid'
524        del(self.student['studycourse']['100'])
525        self.browser.open(self.studycourse_path)
526        self.browser.getLink("Add course list").click()
527        self.browser.getControl("Create course list now").click()
528        # Now 2nd semester course has been added
529        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
530        # Student can add second semester course
531        self.browser.getLink("100").click()
532        self.browser.getLink("Edit course list").click()
533        self.browser.getControl("Add course ticket").click()
534        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
535        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
536        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
537        return
538
539    def test_set_matric_number(self):
540        #payment = createObject('waeup.StudentOnlinePayment')
541        #payment.p_category = u'concessional'
542        #payment.p_id = u'anyid'
543        #payment.p_state = u'paid'
544        #self.student['payments']['anykey'] = payment
545        # Login as student
546        self.browser.open(self.login_path)
547        IWorkflowState(self.student).setState('school fee paid')
548        self.browser.open(self.login_path)
549        self.browser.getControl(name="form.login").value = self.student_id
550        self.browser.getControl(name="form.password").value = 'spwd'
551        self.browser.getControl("Login").click()
552        self.assertRaises(
553            LinkNotFoundError,
554            self.browser.getLink, 'Get Matriculation Number')
555        self.student.matric_number = None
556        site = grok.getSite()
557        site['configuration'].next_matric_integer = 1
558        self.student['studycourse'].certificate.study_mode = 'ug_pt'
559        self.browser.open(self.student_path)
560        self.assertRaises(
561            LinkNotFoundError,
562            self.browser.getLink, 'Download matriculation number slip')
563        self.browser.getLink("Get Matriculation Number").click()
564        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
565            in self.browser.contents)
566        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
567        self.assertRaises(
568            LinkNotFoundError,
569            self.browser.getLink, 'Get Matriculation Number')
570        # Setting matric number is logged.
571        logfile = os.path.join(
572            self.app['datacenter'].storage, 'logs', 'students.log')
573        logcontent = open(logfile).read()
574        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
575                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
576        # Matric Number Slip can be downloaded
577        self.browser.getLink("Download matriculation number slip").click()
578        self.assertEqual(self.browser.headers['Status'], '200 Ok')
579        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
580        path = os.path.join(samples_dir(), 'matric_number_slip.pdf')
581        open(path, 'wb').write(self.browser.contents)
582        print "Sample PDF matric_number_slip.pdf written to %s" % path
583        return
584
585    def test_personal_data_slip(self):
586        # Login as student
587        self.browser.open(self.login_path)
588        IWorkflowState(self.student).setState('school fee paid')
589        self.browser.open(self.login_path)
590        self.browser.getControl(name="form.login").value = self.student_id
591        self.browser.getControl(name="form.password").value = 'spwd'
592        self.browser.getControl("Login").click()
593        self.browser.getLink("Personal Data").click()
594        self.assertRaises(
595            LinkNotFoundError,
596            self.browser.getLink, 'Download personal data slip')
597        self.student.father_name = u'Rudolf'
598        self.browser.open(self.personal_path)
599        self.browser.getLink("Download personal data slip").click()
600        self.assertEqual(self.browser.headers['Status'], '200 Ok')
601        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
602        path = os.path.join(samples_dir(), 'personal_data_slip.pdf')
603        open(path, 'wb').write(self.browser.contents)
604        print "Sample PDF personal_data_slip.pdf written to %s" % path
605        return
606
607    def test_student_course_registration(self):
608        IWorkflowState(self.student).setState('school fee paid')
609        self.browser.open(self.login_path)
610        self.browser.getControl(name="form.login").value = self.student_id
611        self.browser.getControl(name="form.password").value = 'spwd'
612        self.browser.getControl("Login").click()
613        # Now students can add the current study level
614        self.browser.getLink("Study Course").click()
615        self.browser.getLink("Add course list").click()
616        self.assertMatches('...Add current level 100 (Year 1)...',
617                           self.browser.contents)
618        self.browser.getControl("Create course list now").click()
619        # Students can't open the customized pdf course registration slip
620        self.browser.open(
621            self.student_path + '/studycourse/100/course_registration_slip.pdf')
622        self.assertTrue('Forbidden' in self.browser.contents)
623        # They can open slips from the previous session ...
624        self.student['studycourse'].current_level = 200
625        self.browser.open(self.student_path + '/studycourse/100')
626        self.browser.getLink("Download course registration slip").click()
627        self.assertEqual(self.browser.headers['Status'], '200 Ok')
628        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
629        # or if they have registered their course list
630        self.student['studycourse'].current_level = 200
631        IWorkflowState(self.student).setState('courses registered')
632        self.browser.open(self.student_path + '/studycourse/100')
633        self.browser.getLink("Download course registration slip").click()
634        self.assertEqual(self.browser.headers['Status'], '200 Ok')
635        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
636        path = os.path.join(samples_dir(), 'ft_course_registration_slip.pdf')
637        open(path, 'wb').write(self.browser.contents)
638        print "Sample PDF ft_course_registration_slip.pdf written to %s" % path
639
640        self.certificate.study_mode = 'ug_pt'
641        self.browser.open(self.student_path + '/studycourse/100')
642        self.browser.getLink("Download course registration slip").click()
643        self.assertEqual(self.browser.headers['Status'], '200 Ok')
644        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
645        path = os.path.join(samples_dir(), 'pt_course_registration_slip.pdf')
646        open(path, 'wb').write(self.browser.contents)
647        print "Sample PDF pt_course_registration_slip.pdf written to %s" % path
648
649        self.certificate.study_mode = 'special_pg_ft'
650        self.student.matric_number = u'AAU/SPS/FLW/LAW/15/PHD/09504'
651        self.browser.open(self.student_path + '/studycourse/100')
652        self.browser.getLink("Download course registration slip").click()
653        self.assertEqual(self.browser.headers['Status'], '200 Ok')
654        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
655        path = os.path.join(samples_dir(), 'pg_course_registration_slip.pdf')
656        open(path, 'wb').write(self.browser.contents)
657        print "Sample PDF pg_course_registration_slip.pdf written to %s" % path
658
659    def test_student_clearance(self):
660        # Student cant login if their password is not set
661        IWorkflowInfo(self.student).fireTransition('admit')
662        self.browser.open(self.login_path)
663        self.browser.getControl(name="form.login").value = self.student_id
664        self.browser.getControl(name="form.password").value = 'spwd'
665        self.browser.getControl("Login").click()
666        self.assertMatches(
667            '...You logged in...', self.browser.contents)
668        # Admitted student can upload a passport picture
669        self.browser.open(self.student_path + '/change_portrait')
670        ctrl = self.browser.getControl(name='passportuploadedit')
671        file_obj = open(SAMPLE_IMAGE, 'rb')
672        file_ctrl = ctrl.mech_control
673        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
674        self.browser.getControl(
675            name='upload_passportuploadedit').click()
676        self.assertTrue(
677            'src="http://localhost/app/students/E1000000/passport.jpg"'
678            in self.browser.contents)
679        # Student is redirected to the personal data form because
680        # personal data form is not properly filled.
681        self.browser.open(self.student_path + '/start_clearance')
682        self.assertMatches('...Personal data form is not properly filled...',
683                           self.browser.contents)
684        self.assertEqual(self.browser.url, self.student_path + '/edit_personal')
685        self.student.father_name = u'Rudolf'
686        self.browser.open(self.student_path + '/start_clearance')
687        self.assertMatches(
688            '...<h1 class="kofa-content-label">Start clearance</h1>...',
689            self.browser.contents)
690
691    def test_student_accommodation(self):
692        del self.student['accommodation']['2004']
693        self.student['studycourse'].certificate.study_mode = 'dp_ft'
694        # All beds can be assigned
695        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
696        bed1.bed_type = u'regular_male_all'
697        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
698        bed2.bed_type = u'regular_female_all'
699        notify(grok.ObjectModifiedEvent(bed1))
700        notify(grok.ObjectModifiedEvent(bed2))
701        # Login
702        self.browser.open(self.login_path)
703        self.browser.getControl(name="form.login").value = self.student_id
704        self.browser.getControl(name="form.password").value = 'spwd'
705        self.browser.getControl("Login").click()
706        # Students can book accommodation without AC ...
707        self.browser.open(self.acco_path)
708        IWorkflowInfo(self.student).fireTransition('admit')
709        self.browser.getControl("Book accommodation").click()
710        self.assertTrue(
711            'You are not eligible to book accommodation.'
712            in self.browser.contents)
713        self.student['studycourse'].certificate.study_mode = 'ug_ft'
714        self.browser.getControl("Book accommodation").click()
715        self.assertFalse('Activation Code:' in self.browser.contents)
716        self.browser.getControl("Create bed ticket").click()
717        # Bed is randomly selected but, since there is only
718        # one bed for this student, we know that
719        self.assertEqual(self.student['accommodation']['2004'].bed_coordinates,
720            'Hall 1, Block A, Room 101, Bed A (regular_male_all)')
721        # Only the hall name is displayed
722        self.assertEqual(self.student[
723            'accommodation']['2004'].display_coordinates,
724            'Hall 1')
725        self.assertFalse('Hall 1, Block A, Room 101, Bed A'
726            in self.browser.contents)
727        self.assertTrue('<td>Hall 1</td>'
728            in self.browser.contents)
729        return
730
731    def test_handle_courses_by_lecturer(self):
732        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
733        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
734        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
735        # Add course ticket
736        studylevel = createObject(u'waeup.StudentStudyLevel')
737        studylevel.level = 100
738        studylevel.level_session = 2004
739        self.student['studycourse'].addStudentStudyLevel(
740            self.certificate, studylevel)
741        # Assign local Lecturer role for a certificate.
742        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
743        prmlocal = IPrincipalRoleManager(course)
744        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
745        notify(LocalRoleSetEvent(
746            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
747        # Login as lecturer.
748        self.browser.open(self.login_path)
749        self.browser.getControl(name="form.login").value = 'mrslecturer'
750        self.browser.getControl(name="form.password").value = 'mrslecturersecret'
751        self.browser.getControl("Login").click()
752        self.browser.getLink("My Courses").click()
753        self.browser.getLink("COURSE1").click()
754        # Course results can be batch edited via the edit_courses view.
755        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
756        self.app['configuration'].current_academic_session = 2004
757        IWorkflowState(self.student).setState('courses validated')
758        self.browser.open(
759            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
760        self.assertTrue(
761            'input type="text" name="scores:list"'
762            in self.browser.contents)
763        self.browser.getControl(name="scores:list", index=0).value = '55'
764        self.browser.getControl(name="cas:list", index=0).value = '66'
765        self.browser.getControl("Update scores from").click()
766        # New score and ca has been set.
767        self.assertEqual(
768            self.student['studycourse']['100']['COURSE1'].score, 55)
769        self.assertEqual(
770            self.student['studycourse']['100']['COURSE1'].ca, 66)
771        # Score editing has been logged.
772        logfile = os.path.join(
773            self.app['datacenter'].storage, 'logs', 'students.log')
774        logcontent = open(logfile).read()
775        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
776                        'E1000000 100/COURSE1 score updated (55)' in logcontent)
777        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
778                        'E1000000 100/COURSE1 ca updated (66)' in logcontent)
779        # Non-integer scores won't be accepted.
780        self.browser.open(
781            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
782        self.assertTrue('value="55" />' in self.browser.contents)
783        self.browser.getControl(name="scores:list", index=0).value = 'abc'
784        self.browser.getControl("Update scores").click()
785        self.assertTrue('Error: Score(s) and CA(s) of TESTER, Anna have not be updated.'
786            in self.browser.contents)
787        # Scores can be removed.
788        self.browser.open(
789            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
790        self.browser.getControl(name="scores:list", index=0).value = ''
791        self.browser.getControl("Update scores").click()
792        self.assertEqual(
793            self.student['studycourse']['100']['COURSE1'].score, None)
794        logcontent = open(logfile).read()
795        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
796                        'E1000000 100/COURSE1 score updated (None)' in logcontent)
Note: See TracBrowser for help on using the repository browser.