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

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

Remove CustomStudyCourseTranscriptPage?.

Students are allowed to view transcripts. Buttons not yet visible, waiting for confirmation.

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