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

Last change on this file since 13984 was 13964, checked in by Henrik Bettermann, 9 years ago

Get grade from total. Use textwrap for fullname.

  • Property svn:keywords set to Id
File size: 39.8 KB
Line 
1## $Id: test_browser.py 13964 2016-06-21 08:30:14Z 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.browser.getLink("100").click()
444        self.browser.getLink("Edit course list").click()
445        self.browser.getControl("Register course list").click()
446        self.assertTrue('Course registration has ended. Please pay' in self.browser.contents)
447        self.student['payments'].values()[0].approve()
448        self.browser.getControl("Register course list").click()
449        self.assertTrue('Course list has been registered' in self.browser.contents)
450        self.assertEqual(self.student.state, 'courses registered')
451        # Reset student and check if fresh students are always allowed to
452        # register courses.
453        self.student['studycourse'].entry_session = 2004
454        del self.student['payments'][self.student['payments'].keys()[0]]
455        IWorkflowState(self.student).setState('school fee paid')
456        self.browser.open(self.studycourse_path + '/100/edit')
457        self.browser.getControl("Register course list").click()
458        self.assertTrue('Course list has been registered' in self.browser.contents)
459        return
460
461
462    def deactivated_test_student_course_registration(self):
463        # Add more courses
464        self.course2 = createObject('waeup.Course')
465        self.course2.code = 'COURSE2'
466        self.course2.semester = 2
467        self.course2.credits = 10
468        self.course2.passmark = 40
469        self.app['faculties']['fac1']['dep1'].courses.addCourse(
470            self.course2)
471        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
472            self.course2, level=100)
473        self.course3 = createObject('waeup.Course')
474        self.course3.code = 'COURSE3'
475        self.course3.semester = 3
476        self.course3.credits = 10
477        self.course3.passmark = 40
478        self.app['faculties']['fac1']['dep1'].courses.addCourse(
479            self.course3)
480        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
481            self.course3, level=100)
482
483        # Login as student
484        self.browser.open(self.login_path)
485        IWorkflowState(self.student).setState('school fee paid')
486        self.browser.open(self.login_path)
487        self.browser.getControl(name="form.login").value = self.student_id
488        self.browser.getControl(name="form.password").value = 'spwd'
489        self.browser.getControl("Login").click()
490        # Students can add the current study level
491        self.browser.getLink("Study Course").click()
492        self.browser.getLink("Add course list").click()
493        self.assertMatches('...Add current level 100 (Year 1)...',
494                           self.browser.contents)
495        self.browser.getControl("Create course list now").click()
496        # Student has not paid second instalment, therefore a level
497        # with two course ticket was created (semester 1 and combined)
498        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
499        self.browser.getLink("100").click()
500        self.browser.getLink("Edit course list").click()
501        self.browser.getControl("Add course ticket").click()
502        # Student can't add second semester course
503        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
504        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
505        self.assertFalse('<option value="COURSE2">' in self.browser.contents)
506
507        # Let's remove level and see what happens after 2nd instalment payment
508        del(self.student['studycourse']['100'])
509        payment2 = createObject('waeup.StudentOnlinePayment')
510        payment2.p_category = u'schoolfee_2'
511        payment2.p_session = self.student.current_session
512        self.student['payments']['anykey'] = payment2
513        self.browser.open(self.studycourse_path)
514        self.browser.getLink("Add course list").click()
515        self.browser.getControl("Create course list now").click()
516        # Still only 2 tickets have been created since payment ticket
517        # was not paid
518        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
519        payment2.p_state = u'paid'
520        del(self.student['studycourse']['100'])
521        self.browser.open(self.studycourse_path)
522        self.browser.getLink("Add course list").click()
523        self.browser.getControl("Create course list now").click()
524        # Now 2nd semester course has been added
525        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
526        # Student can add second semester course
527        self.browser.getLink("100").click()
528        self.browser.getLink("Edit course list").click()
529        self.browser.getControl("Add course ticket").click()
530        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
531        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
532        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
533        return
534
535    def test_set_matric_number(self):
536        #payment = createObject('waeup.StudentOnlinePayment')
537        #payment.p_category = u'concessional'
538        #payment.p_id = u'anyid'
539        #payment.p_state = u'paid'
540        #self.student['payments']['anykey'] = payment
541        # Login as student
542        self.browser.open(self.login_path)
543        IWorkflowState(self.student).setState('school fee paid')
544        self.browser.open(self.login_path)
545        self.browser.getControl(name="form.login").value = self.student_id
546        self.browser.getControl(name="form.password").value = 'spwd'
547        self.browser.getControl("Login").click()
548        self.assertRaises(
549            LinkNotFoundError,
550            self.browser.getLink, 'Get Matriculation Number')
551        self.student.matric_number = None
552        site = grok.getSite()
553        site['configuration'].next_matric_integer = 1
554        self.student['studycourse'].certificate.study_mode = 'ug_pt'
555        self.browser.open(self.student_path)
556        self.assertRaises(
557            LinkNotFoundError,
558            self.browser.getLink, 'Download matriculation number slip')
559        self.browser.getLink("Get Matriculation Number").click()
560        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
561            in self.browser.contents)
562        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
563        self.assertRaises(
564            LinkNotFoundError,
565            self.browser.getLink, 'Get Matriculation Number')
566        # Setting matric number is logged.
567        logfile = os.path.join(
568            self.app['datacenter'].storage, 'logs', 'students.log')
569        logcontent = open(logfile).read()
570        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
571                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
572        # Matric Number Slip can be downloaded
573        self.browser.getLink("Download matriculation number slip").click()
574        self.assertEqual(self.browser.headers['Status'], '200 Ok')
575        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
576        path = os.path.join(samples_dir(), 'matric_number_slip.pdf')
577        open(path, 'wb').write(self.browser.contents)
578        print "Sample PDF matric_number_slip.pdf written to %s" % path
579        return
580
581    def test_personal_data_slip(self):
582        # Login as student
583        self.browser.open(self.login_path)
584        IWorkflowState(self.student).setState('school fee paid')
585        self.browser.open(self.login_path)
586        self.browser.getControl(name="form.login").value = self.student_id
587        self.browser.getControl(name="form.password").value = 'spwd'
588        self.browser.getControl("Login").click()
589        self.browser.getLink("Personal Data").click()
590        self.assertRaises(
591            LinkNotFoundError,
592            self.browser.getLink, 'Download personal data slip')
593        self.student.father_name = u'Rudolf'
594        self.browser.open(self.personal_path)
595        self.browser.getLink("Download personal data slip").click()
596        self.assertEqual(self.browser.headers['Status'], '200 Ok')
597        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
598        path = os.path.join(samples_dir(), 'personal_data_slip.pdf')
599        open(path, 'wb').write(self.browser.contents)
600        print "Sample PDF personal_data_slip.pdf written to %s" % path
601        return
602
603    def test_student_course_registration(self):
604        IWorkflowState(self.student).setState('school fee paid')
605        self.browser.open(self.login_path)
606        self.browser.getControl(name="form.login").value = self.student_id
607        self.browser.getControl(name="form.password").value = 'spwd'
608        self.browser.getControl("Login").click()
609        # Now students can add the current study level
610        self.browser.getLink("Study Course").click()
611        self.browser.getLink("Add course list").click()
612        self.assertMatches('...Add current level 100 (Year 1)...',
613                           self.browser.contents)
614        self.browser.getControl("Create course list now").click()
615        # Students can't open the customized pdf course registration slip
616        self.browser.open(
617            self.student_path + '/studycourse/100/course_registration_slip.pdf')
618        self.assertTrue('Forbidden' in self.browser.contents)
619        # They can open slips from the previous session ...
620        self.student['studycourse'].current_level = 200
621        self.browser.open(self.student_path + '/studycourse/100')
622        self.browser.getLink("Download course registration slip").click()
623        self.assertEqual(self.browser.headers['Status'], '200 Ok')
624        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
625        # or if they have registered their course list
626        self.student['studycourse'].current_level = 200
627        IWorkflowState(self.student).setState('courses registered')
628        self.browser.open(self.student_path + '/studycourse/100')
629        self.browser.getLink("Download course registration slip").click()
630        self.assertEqual(self.browser.headers['Status'], '200 Ok')
631        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
632        path = os.path.join(samples_dir(), 'ft_course_registration_slip.pdf')
633        open(path, 'wb').write(self.browser.contents)
634        print "Sample PDF ft_course_registration_slip.pdf written to %s" % path
635
636        self.certificate.study_mode = 'ug_pt'
637        self.browser.open(self.student_path + '/studycourse/100')
638        self.browser.getLink("Download course registration slip").click()
639        self.assertEqual(self.browser.headers['Status'], '200 Ok')
640        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
641        path = os.path.join(samples_dir(), 'pt_course_registration_slip.pdf')
642        open(path, 'wb').write(self.browser.contents)
643        print "Sample PDF pt_course_registration_slip.pdf written to %s" % path
644
645        self.certificate.study_mode = 'special_pg_ft'
646        self.student.matric_number = u'AAU/SPS/FLW/LAW/15/PHD/09504'
647        self.browser.open(self.student_path + '/studycourse/100')
648        self.browser.getLink("Download course registration slip").click()
649        self.assertEqual(self.browser.headers['Status'], '200 Ok')
650        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
651        path = os.path.join(samples_dir(), 'pg_course_registration_slip.pdf')
652        open(path, 'wb').write(self.browser.contents)
653        print "Sample PDF pg_course_registration_slip.pdf written to %s" % path
654
655    def test_student_clearance(self):
656        # Student cant login if their password is not set
657        IWorkflowInfo(self.student).fireTransition('admit')
658        self.browser.open(self.login_path)
659        self.browser.getControl(name="form.login").value = self.student_id
660        self.browser.getControl(name="form.password").value = 'spwd'
661        self.browser.getControl("Login").click()
662        self.assertMatches(
663            '...You logged in...', self.browser.contents)
664        # Admitted student can upload a passport picture
665        self.browser.open(self.student_path + '/change_portrait')
666        ctrl = self.browser.getControl(name='passportuploadedit')
667        file_obj = open(SAMPLE_IMAGE, 'rb')
668        file_ctrl = ctrl.mech_control
669        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
670        self.browser.getControl(
671            name='upload_passportuploadedit').click()
672        self.assertTrue(
673            'src="http://localhost/app/students/E1000000/passport.jpg"'
674            in self.browser.contents)
675        # Student is redirected to the personal data form because
676        # personal data form is not properly filled.
677        self.browser.open(self.student_path + '/start_clearance')
678        self.assertMatches('...Personal data form is not properly filled...',
679                           self.browser.contents)
680        self.assertEqual(self.browser.url, self.student_path + '/edit_personal')
681        self.student.father_name = u'Rudolf'
682        self.browser.open(self.student_path + '/start_clearance')
683        self.assertMatches(
684            '...<h1 class="kofa-content-label">Start clearance</h1>...',
685            self.browser.contents)
686
687    def test_student_accommodation(self):
688        del self.student['accommodation']['2004']
689        self.student['studycourse'].certificate.study_mode = 'dp_ft'
690        # All beds can be assigned
691        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
692        bed1.bed_type = u'regular_male_all'
693        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
694        bed2.bed_type = u'regular_female_all'
695        notify(grok.ObjectModifiedEvent(bed1))
696        notify(grok.ObjectModifiedEvent(bed2))
697        # Login
698        self.browser.open(self.login_path)
699        self.browser.getControl(name="form.login").value = self.student_id
700        self.browser.getControl(name="form.password").value = 'spwd'
701        self.browser.getControl("Login").click()
702        # Students can book accommodation without AC ...
703        self.browser.open(self.acco_path)
704        IWorkflowInfo(self.student).fireTransition('admit')
705        self.browser.getControl("Book accommodation").click()
706        self.assertTrue(
707            'You are not eligible to book accommodation.'
708            in self.browser.contents)
709        self.student['studycourse'].certificate.study_mode = 'ug_ft'
710        self.browser.getControl("Book accommodation").click()
711        self.assertFalse('Activation Code:' in self.browser.contents)
712        self.browser.getControl("Create bed ticket").click()
713        # Bed is randomly selected but, since there is only
714        # one bed for this student, we know that
715        self.assertEqual(self.student['accommodation']['2004'].bed_coordinates,
716            'Hall 1, Block A, Room 101, Bed A (regular_male_all)')
717        # Only the hall name is displayed
718        self.assertEqual(self.student[
719            'accommodation']['2004'].display_coordinates,
720            'Hall 1')
721        self.assertFalse('Hall 1, Block A, Room 101, Bed A'
722            in self.browser.contents)
723        self.assertTrue('<td>Hall 1</td>'
724            in self.browser.contents)
725        return
726
727    def test_handle_courses_by_lecturer(self):
728        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
729        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
730        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
731        # Add course ticket
732        studylevel = createObject(u'waeup.StudentStudyLevel')
733        studylevel.level = 100
734        studylevel.level_session = 2004
735        self.student['studycourse'].addStudentStudyLevel(
736            self.certificate, studylevel)
737        # Assign local Lecturer role for a certificate.
738        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
739        prmlocal = IPrincipalRoleManager(course)
740        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
741        notify(LocalRoleSetEvent(
742            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
743        # Login as lecturer.
744        self.browser.open(self.login_path)
745        self.browser.getControl(name="form.login").value = 'mrslecturer'
746        self.browser.getControl(name="form.password").value = 'mrslecturersecret'
747        self.browser.getControl("Login").click()
748        self.browser.getLink("My Courses").click()
749        self.browser.getLink("COURSE1").click()
750        # Course results can be batch edited via the edit_courses view.
751        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
752        self.app['configuration'].current_academic_session = 2004
753        IWorkflowState(self.student).setState('courses validated')
754        self.browser.open(
755            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
756        self.assertTrue(
757            'input type="text" name="scores:list"'
758            in self.browser.contents)
759        self.browser.getControl(name="scores:list", index=0).value = '55'
760        self.browser.getControl(name="cas:list", index=0).value = '66'
761        self.browser.getControl("Update scores from").click()
762        # New score and ca has been set.
763        self.assertEqual(
764            self.student['studycourse']['100']['COURSE1'].score, 55)
765        self.assertEqual(
766            self.student['studycourse']['100']['COURSE1'].ca, 66)
767        # Score editing has been logged.
768        logfile = os.path.join(
769            self.app['datacenter'].storage, 'logs', 'students.log')
770        logcontent = open(logfile).read()
771        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
772                        'E1000000 100/COURSE1 score updated (55)' in logcontent)
773        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
774                        'E1000000 100/COURSE1 ca updated (66)' in logcontent)
775        # Non-integer scores won't be accepted.
776        self.browser.open(
777            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
778        self.assertTrue('value="55" />' in self.browser.contents)
779        self.browser.getControl(name="scores:list", index=0).value = 'abc'
780        self.browser.getControl("Update scores").click()
781        self.assertTrue('Error: Score(s) and CA(s) of TESTER, Anna have not be updated.'
782            in self.browser.contents)
783        # Scores can be removed.
784        self.browser.open(
785            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
786        self.browser.getControl(name="scores:list", index=0).value = ''
787        self.browser.getControl("Update scores").click()
788        self.assertEqual(
789            self.student['studycourse']['100']['COURSE1'].score, None)
790        logcontent = open(logfile).read()
791        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
792                        'E1000000 100/COURSE1 score updated (None)' in logcontent)
Note: See TracBrowser for help on using the repository browser.