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

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

Add imported_gpa and imported_cgpa fields and adjust exporters and batch processors.

  • Property svn:keywords set to Id
File size: 44.0 KB
Line 
1## $Id: test_browser.py 14206 2016-09-29 08:54:32Z 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
45UPLOAD_CSV_TEMPLATE = (
46    'matric_number,student_id,display_fullname,level,code,level_session,'
47    'score,ca\r\n'
48    '234,E1000000,Anna Tester,100,COURSE1,2004,%s,%s\r\n')
49
50class OfficerUITests(StudentsFullSetup):
51    # Tests for Student class views and pages
52
53    layer = FunctionalLayer
54
55    def login_as_lecturer(self):
56        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
57        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
58        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
59        # Add course ticket
60        studylevel = createObject(u'waeup.StudentStudyLevel')
61        studylevel.level = 100
62        studylevel.level_session = 2004
63        self.student['studycourse'].addStudentStudyLevel(
64            self.certificate, studylevel)
65        # Assign local Lecturer role for a certificate.
66        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
67        prmlocal = IPrincipalRoleManager(course)
68        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
69        notify(LocalRoleSetEvent(
70            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
71        # Login as lecturer.
72        self.browser.open(self.login_path)
73        self.browser.getControl(name="form.login").value = 'mrslecturer'
74        self.browser.getControl(
75            name="form.password").value = 'mrslecturersecret'
76        self.browser.getControl("Login").click()
77        # Store reused urls/paths
78        self.course_url = (
79            'http://localhost/app/faculties/fac1/dep1/courses/COURSE1')
80        self.edit_scores_url = '%s/edit_scores' % self.course_url
81        # Set standard parameters
82        self.app['configuration'].current_academic_session = 2004
83        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
84        IWorkflowState(self.student).setState(VALIDATED)
85
86
87    def test_gpa_calculation(self):
88        studylevel = createObject(u'waeup.StudentStudyLevel')
89        studylevel.level = 100
90        studylevel.level_session = 2005
91        self.student['studycourse'].entry_mode = 'ug_ft'
92        self.student['studycourse'].addStudentStudyLevel(
93            self.certificate, studylevel)
94        # First course has been added automatically.
95        # Set score.
96        studylevel['COURSE1'].score = 35
97        studylevel['COURSE1'].ca = 20
98        # GPA is 3.0.
99        self.assertEqual(studylevel.gpa_params[0], 3.0)
100        courseticket = createObject('waeup.CourseTicket')
101        courseticket.code = 'ANYCODE'
102        courseticket.title = u'Any TITLE'
103        courseticket.credits = 13
104        courseticket.score = 44
105        courseticket.ca = 22
106        courseticket.semester = 1
107        courseticket.dcode = u'ANYDCODE'
108        courseticket.fcode = u'ANYFCODE'
109        studylevel['COURSE2'] = courseticket
110        # total credits
111        self.assertEqual(self.student['studycourse']['100'].gpa_params[1], 23)
112        # weigheted credits = 3 * 10 + 4 * 13
113        self.assertEqual(self.student['studycourse']['100'].gpa_params[2], 82.0)
114        # sgpa = 82 / 23
115        self.assertEqual(
116            self.student['studycourse']['100'].gpa_params[0], 3.565)
117        # imported gpa values override calculated values
118        studylevel.imported_gpa = 4.3
119        studylevel.imported_cgpa = 5.4
120        self.assertEqual(self.student['studycourse']['100'].gpa_params[0], 4.3)
121        self.assertEqual(
122            self.student['studycourse']['100'].cumulative_params[0], 5.4)
123        self.assertEqual(self.student['studycourse']['100'].gpa, 4.3)
124        self.student['studycourse'].imported_cgpa = 6.6
125        self.assertEqual(
126            self.student['studycourse'].getTranscriptData()[1], 6.6)
127        return
128
129    def test_grade_weight(self):
130        studylevel = createObject(u'waeup.StudentStudyLevel')
131        studylevel.level = 100
132        studylevel.level_session = 2005
133        self.student['studycourse'].entry_mode = 'ug_ft'
134        self.student['studycourse'].addStudentStudyLevel(
135            self.certificate, studylevel)
136        studylevel['COURSE1'].score = 42
137        studylevel['COURSE1'].ca = 0
138        courseticket = createObject('waeup.CourseTicket')
139        self.assertEqual(studylevel['COURSE1'].weight, 1)
140        self.assertEqual(studylevel['COURSE1'].grade, 'E')
141        self.student['studycourse'].entry_session = 2015
142        self.assertEqual(studylevel['COURSE1'].weight, 0)
143        self.assertEqual(studylevel['COURSE1'].grade, 'F')
144        studylevel['COURSE1'].score = 45
145        self.assertEqual(studylevel['COURSE1'].weight, 2)
146        self.assertEqual(studylevel['COURSE1'].grade, 'D')
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','22'))
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, 22)
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
350    def test_transcripts(self):
351        studylevel = createObject(u'waeup.StudentStudyLevel')
352        studylevel.level = 100
353        studylevel.level_session = 2005
354        self.student['studycourse'].entry_mode = 'ug_ft'
355        self.student['studycourse'].addStudentStudyLevel(
356            self.certificate, studylevel)
357        studylevel2 = createObject(u'waeup.StudentStudyLevel')
358        studylevel2.level = 200
359        studylevel2.level_session = 2006
360        self.student['studycourse']['100']['COURSE1'].score = 33 # no carry-over!
361        self.student['studycourse']['100']['COURSE1'].ca = 22
362        self.student['studycourse'].addStudentStudyLevel(
363            self.certificate, studylevel2)
364        # Add second course (COURSE has been added automatically)
365        courseticket = createObject('waeup.CourseTicket')
366        courseticket.code = 'ANYCODE'
367        courseticket.title = u'Any TITLE'
368        courseticket.credits = 13
369        courseticket.score = 55
370        courseticket.ca = 11
371        courseticket.semester = 1
372        courseticket.dcode = u'ANYDCODE'
373        courseticket.fcode = u'ANYFCODE'
374        self.student['studycourse']['200']['COURSE2'] = courseticket
375        self.assertEqual(self.student['studycourse']['100'].gpa_params_rectified[0], 3.0)
376        self.assertEqual(self.student['studycourse']['200'].gpa_params_rectified[0], 4.0)
377        # Get transcript data
378        td = self.student['studycourse'].getTranscriptData()
379        self.assertEqual(td[0][0]['level_key'], '100')
380        self.assertEqual(td[0][0]['sgpa'], 3.0)
381        self.assertEqual(td[0][0]['level'].level, 100)
382        self.assertEqual(td[0][0]['level'].level_session, 2005)
383        self.assertEqual(td[0][0]['tickets_1'][0].code, 'COURSE1')
384        self.assertEqual(td[0][1]['level_key'], '200')
385        self.assertEqual(td[0][1]['sgpa'], 4.0)
386        self.assertEqual(td[0][1]['level'].level, 200)
387        self.assertEqual(td[0][1]['level'].level_session, 2006)
388        self.assertEqual(td[0][1]['tickets_1'][0].code, 'ANYCODE')
389        self.assertEqual(td[1], 3.57)
390        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
391        self.browser.open(self.student_path + '/studycourse/transcript')
392        self.assertEqual(self.browser.headers['Status'], '200 Ok')
393        self.assertTrue('Transcript' in self.browser.contents)
394        # Officers can open the pdf transcript
395        self.browser.open(self.student_path + '/studycourse/transcript.pdf')
396        self.assertEqual(self.browser.headers['Status'], '200 Ok')
397        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
398        path = os.path.join(samples_dir(), 'transcript.pdf')
399        open(path, 'wb').write(self.browser.contents)
400        print "Sample PDF transcript.pdf written to %s" % path
401
402class StudentUITests(StudentsFullSetup):
403    """Tests for customized student class views and pages
404    """
405
406    layer = FunctionalLayer
407
408    def setUp(self):
409        super(StudentUITests, self).setUp()
410
411        bedticket = BedTicket()
412        bedticket.booking_session = 2004
413        bedticket.bed_type = u'any bed type'
414        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
415        bedticket.bed_coordinates = u'My bed coordinates'
416        self.student['accommodation'].addBedTicket(bedticket)
417
418    def test_student_payments(self):
419        self.certificate.study_mode = 'ug_ft'
420        self.student['studycourse'].entry_session = 2013
421        self.student['studycourse'].certificate.school_fee_1 = 50250.0
422        self.app['configuration']['2004'].union_fee = 1250.0
423        self.app['configuration']['2004'].welfare_fee = 750.0
424        self.student.nationality = u'NG'
425        # Login
426        IWorkflowState(self.student).setState('cleared')
427        self.browser.open(self.login_path)
428        self.browser.getControl(name="form.login").value = self.student_id
429        self.browser.getControl(name="form.password").value = 'spwd'
430        self.browser.getControl("Login").click()
431        # Test school fee payments
432        self.browser.open(self.student_path + '/payments')
433        self.browser.getLink("Add current session payment ticket").click()
434        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
435        self.browser.getControl("Create ticket").click()
436        self.assertTrue('ticket created' in self.browser.contents)
437        value = self.student['payments'].keys()[0]
438        self.browser.getLink(value).click()
439        self.assertTrue('Amount Authorized' in self.browser.contents)
440        self.assertEqual(self.student['payments'][value].amount_auth, 51750.0)
441        self.browser.open(self.browser.url + '/payment_slip.pdf')
442        self.assertEqual(self.browser.headers['Status'], '200 Ok')
443        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
444        path = os.path.join(samples_dir(), 'payment_slip.pdf')
445        open(path, 'wb').write(self.browser.contents)
446        print "Sample PDF payment_slip.pdf written to %s" % path
447        # Another school fee payment cannot be added
448        self.student['payments'][value].approve()
449        self.browser.open(self.student_path + '/payments')
450        self.browser.getLink("Add current session payment ticket").click()
451        self.browser.getControl(name="form.p_category").value = ['schoolfee']
452        self.browser.getControl("Create ticket").click()
453        self.assertTrue(
454            'You must chose a payment which includes additional fees'
455            in self.browser.contents)
456        #self.assertTrue(
457        #    'Another school fee payment for this session has already been made'
458        #    in self.browser.contents)
459        # Test hostel maintenance payments
460        self.browser.open(self.student_path + '/payments')
461        self.browser.getLink("Add current session payment ticket").click()
462        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
463        self.browser.getControl("Create ticket").click()
464        self.assertTrue('ticket created' in self.browser.contents)
465        value = self.student['payments'].keys()[1]
466        self.browser.getLink(value).click()
467        self.assertTrue('<span>My bed coordinates</span>' in self.browser.contents)
468        self.assertEqual(self.student['payments'][value].amount_auth, 876.0)
469        return
470
471    def test_late_registration(self):
472        # Login
473        delta = timedelta(days=10)
474        self.app['configuration'][
475            '2004'].coursereg_deadline = datetime.now(pytz.utc) - delta
476        IWorkflowState(self.student).setState('school fee paid')
477        # Current session is 2004. Here we test course registration for
478        # returning students.
479        self.student['studycourse'].entry_session = 2003
480        self.browser.open(self.login_path)
481        self.browser.getControl(name="form.login").value = self.student_id
482        self.browser.getControl(name="form.password").value = 'spwd'
483        self.browser.getControl("Login").click()
484        self.browser.open(self.payments_path)
485        self.browser.open(self.payments_path + '/addop')
486        self.browser.getControl(name="form.p_category").value = ['late_registration']
487        self.browser.getControl("Create ticket").click()
488        self.assertMatches('...ticket created...',
489                           self.browser.contents)
490        self.browser.getLink("Study Course").click()
491        self.browser.getLink("Add course list").click()
492        self.assertMatches('...Add current level 100 (Year 1)...',
493                           self.browser.contents)
494        self.browser.getControl("Create course list now").click()
495        self.student['studycourse']['100']['COURSE1'].score = 67
496        self.browser.getLink("100").click()
497        # Course results can't be seen
498        self.assertFalse('<td>67</td>' in self.browser.contents)
499        self.browser.getLink("Edit course list").click()
500        self.assertFalse('<td>67</td>' in self.browser.contents)
501        self.browser.getControl("Register course list").click()
502        self.assertTrue('Course registration has ended. Please pay' in self.browser.contents)
503        self.student['payments'].values()[0].approve()
504        self.browser.getControl("Register course list").click()
505        self.assertTrue('Course list has been registered' in self.browser.contents)
506        self.assertEqual(self.student.state, 'courses registered')
507        # Reset student and check if fresh students are always allowed to
508        # register courses.
509        self.student['studycourse'].entry_session = 2004
510        del self.student['payments'][self.student['payments'].keys()[0]]
511        IWorkflowState(self.student).setState('school fee paid')
512        self.browser.open(self.studycourse_path + '/100/edit')
513        self.browser.getControl("Register course list").click()
514        self.assertTrue('Course list has been registered' in self.browser.contents)
515        return
516
517
518    def deactivated_test_student_course_registration(self):
519        # Add more courses
520        self.course2 = createObject('waeup.Course')
521        self.course2.code = 'COURSE2'
522        self.course2.semester = 2
523        self.course2.credits = 10
524        self.course2.passmark = 40
525        self.app['faculties']['fac1']['dep1'].courses.addCourse(
526            self.course2)
527        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
528            self.course2, level=100)
529        self.course3 = createObject('waeup.Course')
530        self.course3.code = 'COURSE3'
531        self.course3.semester = 3
532        self.course3.credits = 10
533        self.course3.passmark = 40
534        self.app['faculties']['fac1']['dep1'].courses.addCourse(
535            self.course3)
536        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
537            self.course3, level=100)
538
539        # Login as student
540        self.browser.open(self.login_path)
541        IWorkflowState(self.student).setState('school fee paid')
542        self.browser.open(self.login_path)
543        self.browser.getControl(name="form.login").value = self.student_id
544        self.browser.getControl(name="form.password").value = 'spwd'
545        self.browser.getControl("Login").click()
546        # Students can add the current study level
547        self.browser.getLink("Study Course").click()
548        self.browser.getLink("Add course list").click()
549        self.assertMatches('...Add current level 100 (Year 1)...',
550                           self.browser.contents)
551        self.browser.getControl("Create course list now").click()
552        # Student has not paid second instalment, therefore a level
553        # with two course ticket was created (semester 1 and combined)
554        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
555        self.browser.getLink("100").click()
556        self.browser.getLink("Edit course list").click()
557        self.browser.getControl("Add course ticket").click()
558        # Student can't add second semester course
559        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
560        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
561        self.assertFalse('<option value="COURSE2">' in self.browser.contents)
562
563        # Let's remove level and see what happens after 2nd instalment payment
564        del(self.student['studycourse']['100'])
565        payment2 = createObject('waeup.StudentOnlinePayment')
566        payment2.p_category = u'schoolfee_2'
567        payment2.p_session = self.student.current_session
568        self.student['payments']['anykey'] = payment2
569        self.browser.open(self.studycourse_path)
570        self.browser.getLink("Add course list").click()
571        self.browser.getControl("Create course list now").click()
572        # Still only 2 tickets have been created since payment ticket
573        # was not paid
574        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
575        payment2.p_state = u'paid'
576        del(self.student['studycourse']['100'])
577        self.browser.open(self.studycourse_path)
578        self.browser.getLink("Add course list").click()
579        self.browser.getControl("Create course list now").click()
580        # Now 2nd semester course has been added
581        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
582        # Student can add second semester course
583        self.browser.getLink("100").click()
584        self.browser.getLink("Edit course list").click()
585        self.browser.getControl("Add course ticket").click()
586        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
587        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
588        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
589        return
590
591    def test_set_matric_number(self):
592        #payment = createObject('waeup.StudentOnlinePayment')
593        #payment.p_category = u'concessional'
594        #payment.p_id = u'anyid'
595        #payment.p_state = u'paid'
596        #self.student['payments']['anykey'] = payment
597        # Login as student
598        self.browser.open(self.login_path)
599        IWorkflowState(self.student).setState('school fee paid')
600        self.browser.open(self.login_path)
601        self.browser.getControl(name="form.login").value = self.student_id
602        self.browser.getControl(name="form.password").value = 'spwd'
603        self.browser.getControl("Login").click()
604        self.assertRaises(
605            LinkNotFoundError,
606            self.browser.getLink, 'Get Matriculation Number')
607        self.student.matric_number = None
608        site = grok.getSite()
609        site['configuration'].next_matric_integer = 1
610        self.student['studycourse'].certificate.study_mode = 'ug_pt'
611        self.browser.open(self.student_path)
612        self.assertRaises(
613            LinkNotFoundError,
614            self.browser.getLink, 'Download matriculation number slip')
615        self.browser.getLink("Get Matriculation Number").click()
616        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
617            in self.browser.contents)
618        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
619        self.assertRaises(
620            LinkNotFoundError,
621            self.browser.getLink, 'Get Matriculation Number')
622        # Setting matric number is logged.
623        logfile = os.path.join(
624            self.app['datacenter'].storage, 'logs', 'students.log')
625        logcontent = open(logfile).read()
626        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
627                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
628        # Matric Number Slip can be downloaded
629        self.browser.getLink("Download matriculation number 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(), 'matric_number_slip.pdf')
633        open(path, 'wb').write(self.browser.contents)
634        print "Sample PDF matric_number_slip.pdf written to %s" % path
635        return
636
637    def test_personal_data_slip(self):
638        # Login as student
639        self.browser.open(self.login_path)
640        IWorkflowState(self.student).setState('school fee paid')
641        self.browser.open(self.login_path)
642        self.browser.getControl(name="form.login").value = self.student_id
643        self.browser.getControl(name="form.password").value = 'spwd'
644        self.browser.getControl("Login").click()
645        self.browser.getLink("Personal Data").click()
646        self.assertRaises(
647            LinkNotFoundError,
648            self.browser.getLink, 'Download personal data slip')
649        self.student.father_name = u'Rudolf'
650        self.browser.open(self.personal_path)
651        self.browser.getLink("Download personal data slip").click()
652        self.assertEqual(self.browser.headers['Status'], '200 Ok')
653        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
654        path = os.path.join(samples_dir(), 'personal_data_slip.pdf')
655        open(path, 'wb').write(self.browser.contents)
656        print "Sample PDF personal_data_slip.pdf written to %s" % path
657        return
658
659    def test_student_course_registration(self):
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        # Now students can add the current study level
666        self.browser.getLink("Study Course").click()
667        self.browser.getLink("Add course list").click()
668        self.assertMatches('...Add current level 100 (Year 1)...',
669                           self.browser.contents)
670        self.browser.getControl("Create course list now").click()
671        # Students can't open the customized pdf course registration slip
672        self.browser.open(
673            self.student_path + '/studycourse/100/course_registration_slip.pdf')
674        self.assertTrue('Forbidden' in self.browser.contents)
675        # They can open slips from the previous session ...
676        self.student['studycourse'].current_level = 200
677        self.browser.open(self.student_path + '/studycourse/100')
678        self.browser.getLink("Download course registration slip").click()
679        self.assertEqual(self.browser.headers['Status'], '200 Ok')
680        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
681        # or if they have registered their course list
682        self.student['studycourse'].current_level = 200
683        IWorkflowState(self.student).setState('courses registered')
684        self.browser.open(self.student_path + '/studycourse/100')
685        self.browser.getLink("Download course registration slip").click()
686        self.assertEqual(self.browser.headers['Status'], '200 Ok')
687        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
688        path = os.path.join(samples_dir(), 'ft_course_registration_slip.pdf')
689        open(path, 'wb').write(self.browser.contents)
690        print "Sample PDF ft_course_registration_slip.pdf written to %s" % path
691
692        self.certificate.study_mode = 'ug_pt'
693        self.browser.open(self.student_path + '/studycourse/100')
694        self.browser.getLink("Download course registration slip").click()
695        self.assertEqual(self.browser.headers['Status'], '200 Ok')
696        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
697        path = os.path.join(samples_dir(), 'pt_course_registration_slip.pdf')
698        open(path, 'wb').write(self.browser.contents)
699        print "Sample PDF pt_course_registration_slip.pdf written to %s" % path
700
701        self.certificate.study_mode = 'special_pg_ft'
702        self.student.matric_number = u'AAU/SPS/FLW/LAW/15/PHD/09504'
703        self.browser.open(self.student_path + '/studycourse/100')
704        self.browser.getLink("Download course registration slip").click()
705        self.assertEqual(self.browser.headers['Status'], '200 Ok')
706        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
707        path = os.path.join(samples_dir(), 'pg_course_registration_slip.pdf')
708        open(path, 'wb').write(self.browser.contents)
709        print "Sample PDF pg_course_registration_slip.pdf written to %s" % path
710
711    def test_student_clearance(self):
712        # Student cant login if their password is not set
713        IWorkflowInfo(self.student).fireTransition('admit')
714        self.browser.open(self.login_path)
715        self.browser.getControl(name="form.login").value = self.student_id
716        self.browser.getControl(name="form.password").value = 'spwd'
717        self.browser.getControl("Login").click()
718        self.assertMatches(
719            '...You logged in...', self.browser.contents)
720        # Admitted student can upload a passport picture
721        self.browser.open(self.student_path + '/change_portrait')
722        ctrl = self.browser.getControl(name='passportuploadedit')
723        file_obj = open(SAMPLE_IMAGE, 'rb')
724        file_ctrl = ctrl.mech_control
725        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
726        self.browser.getControl(
727            name='upload_passportuploadedit').click()
728        self.assertTrue(
729            'src="http://localhost/app/students/E1000000/passport.jpg"'
730            in self.browser.contents)
731        # Student is redirected to the personal data form because
732        # personal data form is not properly filled.
733        self.browser.open(self.student_path + '/start_clearance')
734        self.assertMatches('...Personal data form is not properly filled...',
735                           self.browser.contents)
736        self.assertEqual(self.browser.url, self.student_path + '/edit_personal')
737        self.student.father_name = u'Rudolf'
738        self.browser.open(self.student_path + '/start_clearance')
739        self.assertMatches(
740            '...<h1 class="kofa-content-label">Start clearance</h1>...',
741            self.browser.contents)
742
743    def test_student_accommodation(self):
744        del self.student['accommodation']['2004']
745        self.student['studycourse'].certificate.study_mode = 'dp_ft'
746        # All beds can be assigned
747        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
748        bed1.bed_type = u'regular_male_all'
749        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
750        bed2.bed_type = u'regular_female_all'
751        notify(grok.ObjectModifiedEvent(bed1))
752        notify(grok.ObjectModifiedEvent(bed2))
753        # Login
754        self.browser.open(self.login_path)
755        self.browser.getControl(name="form.login").value = self.student_id
756        self.browser.getControl(name="form.password").value = 'spwd'
757        self.browser.getControl("Login").click()
758        # Students can book accommodation without AC ...
759        self.browser.open(self.acco_path)
760        IWorkflowInfo(self.student).fireTransition('admit')
761        self.browser.getControl("Book accommodation").click()
762        self.assertTrue(
763            'You are not eligible to book accommodation.'
764            in self.browser.contents)
765        self.student['studycourse'].certificate.study_mode = 'ug_ft'
766        self.browser.getControl("Book accommodation").click()
767        self.assertFalse('Activation Code:' in self.browser.contents)
768        self.browser.getControl("Create bed ticket").click()
769        # Bed is randomly selected but, since there is only
770        # one bed for this student, we know that
771        self.assertEqual(self.student['accommodation']['2004'].bed_coordinates,
772            'Hall 1, Block A, Room 101, Bed A (regular_male_all)')
773        # Only the hall name is displayed
774        self.assertEqual(self.student[
775            'accommodation']['2004'].display_coordinates,
776            'Hall 1')
777        self.assertFalse('Hall 1, Block A, Room 101, Bed A'
778            in self.browser.contents)
779        self.assertTrue('<td>Hall 1</td>'
780            in self.browser.contents)
781        return
782
783    def test_handle_courses_by_lecturer(self):
784        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
785        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
786        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
787        # Add course ticket
788        studylevel = createObject(u'waeup.StudentStudyLevel')
789        studylevel.level = 100
790        studylevel.level_session = 2004
791        self.student['studycourse'].addStudentStudyLevel(
792            self.certificate, studylevel)
793        # Assign local Lecturer role for a certificate.
794        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
795        prmlocal = IPrincipalRoleManager(course)
796        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
797        notify(LocalRoleSetEvent(
798            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
799        # Login as lecturer.
800        self.browser.open(self.login_path)
801        self.browser.getControl(name="form.login").value = 'mrslecturer'
802        self.browser.getControl(name="form.password").value = 'mrslecturersecret'
803        self.browser.getControl("Login").click()
804        self.browser.getLink("My Courses").click()
805        self.browser.getLink("COURSE1").click()
806        # Course results can be batch edited via the edit_courses view.
807        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
808        self.app['configuration'].current_academic_session = 2004
809        IWorkflowState(self.student).setState('courses validated')
810        self.browser.open(
811            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
812        self.assertTrue(
813            'input type="text" name="scores:list"'
814            in self.browser.contents)
815        self.browser.getControl(name="scores:list", index=0).value = '55'
816        self.browser.getControl(name="cas:list", index=0).value = '22'
817        self.browser.getControl("Update scores from").click()
818        # New score and ca has been set.
819        self.assertEqual(
820            self.student['studycourse']['100']['COURSE1'].score, 55)
821        self.assertEqual(
822            self.student['studycourse']['100']['COURSE1'].ca, 22)
823        # Score editing has been logged.
824        logfile = os.path.join(
825            self.app['datacenter'].storage, 'logs', 'students.log')
826        logcontent = open(logfile).read()
827        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
828                        'E1000000 100/COURSE1 score updated (55)' in logcontent)
829        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
830                        'E1000000 100/COURSE1 ca updated (22)' in logcontent)
831        # Non-integer scores won't be accepted.
832        self.browser.open(
833            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
834        self.assertTrue('value="55" />' in self.browser.contents)
835        self.browser.getControl(name="scores:list", index=0).value = 'abc'
836        self.browser.getControl("Update scores").click()
837        self.assertTrue('Error: Score(s) and CA(s) of TESTER, Anna have not be updated.'
838            in self.browser.contents)
839        # Scores can be removed.
840        self.browser.open(
841            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
842        self.browser.getControl(name="scores:list", index=0).value = ''
843        self.browser.getControl("Update scores").click()
844        self.assertEqual(
845            self.student['studycourse']['100']['COURSE1'].score, None)
846        logcontent = open(logfile).read()
847        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
848                        'E1000000 100/COURSE1 score updated (None)' in logcontent)
849
850
851    def test_student_view_transcript(self):
852        # Student cant login if their password is not set
853        IWorkflowInfo(self.student).fireTransition('admit')
854        self.browser.open(self.login_path)
855        self.browser.getControl(name="form.login").value = self.student_id
856        self.browser.getControl(name="form.password").value = 'spwd'
857        self.browser.getControl("Login").click()
858        self.assertMatches(
859            '...You logged in...', self.browser.contents)
860        # Students can view the transcript
861        self.browser.open(self.studycourse_path)
862        self.browser.getLink("Transcript").click()
863        self.browser.getLink("Academic Transcript").click()
864        self.assertEqual(self.browser.headers['Status'], '200 Ok')
865        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
Note: See TracBrowser for help on using the repository browser.