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

Last change on this file since 15178 was 15178, checked in by Henrik Bettermann, 6 years ago

https://aaue-trac.waeup.org/ticket/487#comment:4

The restitution was only for returning students of 2016/2017. Hence, it is only valid for 2016 payment session returning students.

  • Property svn:keywords set to Id
File size: 68.4 KB
Line 
1## $Id: test_browser.py 15178 2018-09-26 14:15:21Z 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, PAID
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.kofa.applicants.container import ApplicantsContainer
41from waeup.aaue.testing import FunctionalLayer
42
43SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
44
45
46UPLOAD_CSV_TEMPLATE = (
47    'matric_number,student_id,display_fullname,level,code,level_session,'
48    'score,ca\r\n'
49    '234,E1000000,Anna Tester,100,COURSE1,2004,%s,%s\r\n')
50
51class OfficerUITests(StudentsFullSetup):
52    # Tests for Student class views and pages
53
54    layer = FunctionalLayer
55
56    def login_as_lecturer(self):
57        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
58        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
59        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
60        # Add course ticket
61        studylevel = createObject(u'waeup.StudentStudyLevel')
62        studylevel.level = 100
63        studylevel.level_session = 2004
64        self.student['studycourse'].addStudentStudyLevel(
65            self.certificate, studylevel)
66        # Assign local Lecturer role for a certificate.
67        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
68        prmlocal = IPrincipalRoleManager(course)
69        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
70        notify(LocalRoleSetEvent(
71            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
72        # Login as lecturer.
73        self.browser.open(self.login_path)
74        self.browser.getControl(name="form.login").value = 'mrslecturer'
75        self.browser.getControl(
76            name="form.password").value = 'mrslecturersecret'
77        self.browser.getControl("Login").click()
78        # Store reused urls/paths
79        self.course_url = (
80            'http://localhost/app/faculties/fac1/dep1/courses/COURSE1')
81        self.edit_scores_url = '%s/edit_scores' % self.course_url
82        self.edit_prev_scores_url = '%s/edit_prev_scores' % self.course_url
83        # Set standard parameters
84        self.app['configuration'].current_academic_session = 2004
85        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
86        IWorkflowState(self.student).setState(VALIDATED)
87
88
89    def test_gpa_calculation(self):
90        studylevel = createObject(u'waeup.StudentStudyLevel')
91        studylevel.level = 100
92        studylevel.level_session = 2005
93        self.student['studycourse'].entry_mode = 'ug_ft'
94        self.student['studycourse'].addStudentStudyLevel(
95            self.certificate, studylevel)
96        # First course has been added automatically.
97        # Set score.
98        studylevel['COURSE1'].score = 35
99        studylevel['COURSE1'].ca = 20
100        # GPA is 3.0.
101        self.assertEqual(studylevel.gpa_params[0], 3.0)
102        courseticket = createObject('waeup.CourseTicket')
103        courseticket.code = 'ANYCODE'
104        courseticket.title = u'Any TITLE'
105        courseticket.credits = 13
106        courseticket.score = 44
107        courseticket.ca = 22
108        courseticket.semester = 1
109        courseticket.dcode = u'ANYDCODE'
110        courseticket.fcode = u'ANYFCODE'
111        studylevel['COURSE2'] = courseticket
112        # total credits
113        self.assertEqual(self.student['studycourse']['100'].gpa_params[1], 23)
114        # weigheted credits = 3 * 10 + 4 * 13
115        self.assertEqual(self.student['studycourse']['100'].gpa_params[2], 82.0)
116        # sgpa = 82 / 23
117        self.assertEqual(
118            self.student['studycourse']['100'].gpa_params[0], 3.5652173913043477)
119        # imported gpa values override calculated values
120        studylevel.imported_gpa = 4.3
121        studylevel.imported_cgpa = 5.4
122        self.assertEqual(self.student['studycourse']['100'].gpa_params[0], 4.3)
123        self.assertEqual(
124            self.student['studycourse']['100'].cumulative_params[0], 5.4)
125        self.assertEqual(self.student['studycourse']['100'].gpa, '4.30')
126        self.student['studycourse'].imported_cgpa = 6.6
127        self.assertEqual(
128            self.student['studycourse'].getTranscriptData()[1], 6.6)
129        return
130
131    def test_grade_weight(self):
132        studylevel = createObject(u'waeup.StudentStudyLevel')
133        studylevel.level = 100
134        studylevel.level_session = 2005
135        self.course.passmark = 40
136        self.student['studycourse'].entry_mode = 'ug_ft'
137        self.student['studycourse'].addStudentStudyLevel(
138            self.certificate, studylevel)
139        studylevel['COURSE1'].score = 42
140        studylevel['COURSE1'].ca = 0
141        courseticket = createObject('waeup.CourseTicket')
142        self.assertEqual(studylevel['COURSE1'].weight, 1)
143        self.assertEqual(studylevel['COURSE1'].grade, 'E')
144        self.assertEqual(studylevel['COURSE1'].weight, 1)
145        self.assertEqual(studylevel['COURSE1'].grade, 'E')
146        studylevel['COURSE1'].score = 45
147        self.assertEqual(studylevel['COURSE1'].weight, 2)
148        self.assertEqual(studylevel['COURSE1'].grade, 'D')
149        return
150
151    def test_manage_payments(self):
152        # Add missing configuration data
153        self.app['configuration']['2004'].gown_fee = 150.0
154        self.app['configuration']['2004'].transfer_fee = 90.0
155        self.app['configuration']['2004'].booking_fee = 150.0
156        self.app['configuration']['2004'].maint_fee = 180.0
157        self.app['configuration']['2004'].late_fee = 80.0
158
159        # Managers can add online payment tickets
160        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
161        self.browser.open(self.payments_path)
162        self.browser.getLink("Add current session payment ticket").click()
163        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
164        self.browser.getControl("Create ticket").click()
165        self.assertMatches('...Wrong state...',
166                           self.browser.contents)
167        IWorkflowState(self.student).setState('cleared')
168        self.browser.open(self.payments_path + '/addop')
169        self.app['configuration']['2004'].clearance_fee = 666.0
170        self.browser.getControl(name="form.p_category").value = ['clearance_incl']
171        self.browser.getControl("Create ticket").click()
172        ctrl = self.browser.getControl(name='val_id')
173        cpt_value = ctrl.options[0]
174        # School fee payment ticket can be added ...
175        self.student['studycourse'].certificate.school_fee_1 = 6666.0
176        self.student.nationality = u'NG'
177        self.browser.open(self.payments_path + '/addop')
178        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
179        self.browser.getControl("Create ticket").click()
180        self.assertMatches('...ticket created...',
181                           self.browser.contents)
182        # ... but not paid through the query_history page.
183        ctrl = self.browser.getControl(name='val_id')
184        sfpt_value = ctrl.options[1]
185        self.student['studycourse'].entry_session = 2013
186        self.browser.open(self.payments_path + '/' + sfpt_value)
187        self.browser.getLink("Query eTranzact History").click()
188        self.assertMatches('...alert-danger">Please pay acceptance fee first...',
189                           self.browser.contents)
190        # If clearance/acceptance fee is paid ...
191        self.student['payments'][cpt_value].approveStudentPayment()
192        self.browser.getLink("Query eTranzact History").click()
193        # ... query_history page is accessible.
194        self.assertMatches(
195            '...<h1 class="kofa-content-label">Requery eTranzact History</h1>...',
196            self.browser.contents)
197        # Managers can open school fee payment slip
198        self.browser.open(self.payments_path + '/' + sfpt_value)
199        self.browser.getLink("Download payment slip").click()
200        self.assertEqual(self.browser.headers['Status'], '200 Ok')
201        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
202        # If school fee ticket is paid, the student is automatically set to
203        # school fee paid...
204        ticket = self.student['payments'][sfpt_value].approveStudentPayment()
205        self.assertEqual(self.student.state, 'school fee paid')
206        # ... no further school fee ticket can be added.
207        self.browser.open(self.payments_path + '/addop')
208        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
209        self.browser.getControl("Create ticket").click()
210        self.assertMatches('...Wrong state...',
211                           self.browser.contents)
212        self.browser.open(self.payments_path + '/addop')
213        self.browser.getControl(name="form.p_category").value = ['late_registration']
214        self.browser.getControl("Create ticket").click()
215        self.assertMatches('...ticket created...',
216                           self.browser.contents)
217        return
218
219    def test_for_instalment_payments(self):
220        configuration_1 = createObject('waeup.SessionConfiguration')
221        configuration_1.academic_session = 2015
222        self.app['configuration'].addSessionConfiguration(configuration_1)
223        self.student['studycourse'].certificate.study_mode = 'ug_pt'
224        self.student['studycourse'].certificate.school_fee_1 = 6666.0
225        self.app['configuration']['2015'].union_fee = 1250.0
226        self.app['configuration']['2015'].welfare_fee = 750.0
227        self.student.nationality = u'NG'
228        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
229        self.browser.open(self.payments_path + '/addop')
230        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
231        self.browser.getControl("Create ticket").click()
232        self.assertTrue(
233            'Part-time students are not allowed' in self.browser.contents)
234        self.student['studycourse'].certificate.study_mode = 'ug_ft'
235        self.browser.open(self.payments_path + '/addop')
236        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
237        self.browser.getControl("Create ticket").click()
238        self.assertTrue('You are not allowed to pay by instalments.'
239            in self.browser.contents)
240        IWorkflowState(self.student).setState('cleared')
241        self.student['studycourse'].entry_session = 2015
242        self.student['studycourse'].current_session = 2015
243        self.browser.open(self.payments_path + '/addop')
244        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
245        self.browser.getControl("Create ticket").click()
246        self.assertTrue('ticket created' in self.browser.contents)
247        # We can't add the 2nd instalment ticket because the
248        # first one has not yet been approved.
249        #self.browser.open(self.payments_path + '/addop')
250        #self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
251        #self.browser.getControl("Create ticket").click()
252        #self.assertMatches('...1st school fee instalment has not yet been paid...',
253        #                   self.browser.contents)
254        # Ok, then we approve the first instalment ...
255        self.browser.open(self.payments_path)
256        ctrl = self.browser.getControl(name='val_id')
257        p_id = ctrl.options[0]
258        self.browser.open(self.payments_path + '/' + p_id + '/approve')
259        # ... add the second instalment ...
260        self.browser.open(self.payments_path + '/addop')
261        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
262        self.browser.getControl("Create ticket").click()
263        self.assertTrue('ticket created' in self.browser.contents)
264        # ... approve the second instalment ...
265        ctrl = self.browser.getControl(name='val_id')
266        p_id = ctrl.options[1]
267        self.browser.open(self.payments_path + '/' + p_id + '/approve')
268        self.assertEqual(self.student['payments'].values()[0].p_category, 'schoolfee_1')
269        self.assertEqual(self.student['payments'].values()[1].p_category, 'schoolfee_2')
270        # (6666-250)/2 + 1250 + 750 - 500 + 250
271        self.assertEqual(self.student['payments'].values()[0].amount_auth, 4958.0)
272        # (6666-250)/2 + 250
273        self.assertEqual(self.student['payments'].values()[1].amount_auth, 3458.0)
274        # The  two payments belong to the same session and level.
275        self.assertEqual(self.student['payments'].values()[0].p_session, 2015)
276        self.assertEqual(self.student['payments'].values()[0].p_level, 100)
277        self.assertEqual(self.student['payments'].values()[1].p_session, 2015)
278        self.assertEqual(self.student['payments'].values()[1].p_level, 100)
279
280        # Returning student
281        configuration_2 = createObject('waeup.SessionConfiguration')
282        configuration_2.academic_session = 2016
283        self.app['configuration'].addSessionConfiguration(configuration_2)
284        self.student['studycourse'].certificate.school_fee_2 = 5666.0
285        self.app['configuration']['2016'].union_fee = 1250.0
286        self.app['configuration']['2016'].welfare_fee = 750.0
287        self.student.father_name = u'Albert'
288        IWorkflowState(self.student).setState('returning')
289        self.browser.open(self.payments_path + '/addop')
290        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
291        self.browser.getControl("Create ticket").click()
292        self.browser.open(self.payments_path + '/addop')
293        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
294        self.browser.getControl("Create ticket").click()
295        # Student is still in the first  session.
296        self.assertTrue('This type of payment' in self.browser.contents)
297        self.browser.open(self.payments_path)
298        ctrl = self.browser.getControl(name='val_id')
299        p_id = ctrl.options[2]
300        self.browser.open(self.payments_path + '/' + p_id + '/approve')
301        self.browser.open(self.payments_path + '/addop')
302        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
303        self.browser.getControl("Create ticket").click()
304        self.assertTrue('ticket created' in self.browser.contents)
305        # (5666-250)/2 + 1250 + 750 - 500 + 250
306        self.assertEqual(self.student['payments'].values()[2].amount_auth, 4458.0)
307        # (5666-250)/2 + 250
308        self.assertEqual(self.student['payments'].values()[3].amount_auth, 2958.0)
309        # The last two payments belong to the same session and level.
310        self.assertEqual(self.student['payments'].values()[2].p_session, 2016)
311        self.assertEqual(self.student['payments'].values()[2].p_level, 200)
312        self.assertEqual(self.student['payments'].values()[3].p_session, 2016)
313        self.assertEqual(self.student['payments'].values()[3].p_level, 200)
314        return
315
316    def test_manage_payments_bypass_ac_creation(self):
317        self.student['studycourse'].certificate.school_fee_1 = 6666.0
318        self.student.nationality = u'NG'
319        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
320        self.browser.open(self.payments_path)
321        IWorkflowState(self.student).setState('cleared')
322        self.browser.getLink("Add current session payment ticket").click()
323        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
324        self.browser.getControl("Create ticket").click()
325        ctrl = self.browser.getControl(name='val_id')
326        value = ctrl.options[0]
327        self.browser.getLink(value).click()
328        payment_url = self.browser.url
329        logfile = os.path.join(
330            self.app['datacenter'].storage, 'logs', 'students.log')
331        # The ticket can be found in the payments_catalog
332        cat = queryUtility(ICatalog, name='payments_catalog')
333        results = list(cat.searchResults(p_state=('unpaid', 'unpaid')))
334        self.assertTrue(len(results), 1)
335        self.assertTrue(results[0] is self.student['payments'][value])
336        # Managers can approve the payment
337        self.browser.open(payment_url)
338        self.browser.getLink("Approve payment").click()
339        self.assertMatches('...Payment approved...',
340                          self.browser.contents)
341        # Approval is logged in students.log ...
342        logcontent = open(logfile).read()
343        self.assertTrue(
344            'zope.mgr - students.browser.OnlinePaymentApproveView '
345            '- E1000000 - schoolfee_incl payment approved'
346            in logcontent)
347        # ... and in payments.log
348        logfile = os.path.join(
349            self.app['datacenter'].storage, 'logs', 'payments.log')
350        logcontent = open(logfile).read()
351        self.assertTrue(
352            '"zope.mgr",E1000000,%s,schoolfee_incl,6666.0,AP,,,,,,\n' % value
353            in logcontent)
354        # Student is in state school fee paid, no activation
355        # code was necessary.
356        self.assertEqual(self.student.state, 'school fee paid')
357        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
358        return
359
360    def test_scores_csv_upload_available(self):
361        # lecturers can upload a CSV file to set values.
362        self.login_as_lecturer()
363        # set value to change from
364        self.student['studycourse']['100']['COURSE1'].score = 55
365        self.app['configuration']['2004'].score_editing_enabled = ['ug_ft']
366        self.browser.open(self.edit_scores_url)
367        upload_ctrl = self.browser.getControl(name='uploadfile:file')
368        upload_file = StringIO(UPLOAD_CSV_TEMPLATE % ('65','22'))
369        upload_ctrl.add_file(upload_file, 'text/csv', 'myscores.csv')
370        self.browser.getControl("Update editable scores from").click()
371        # value changed
372        self.assertEqual(
373            self.student['studycourse']['100']['COURSE1'].score, 65)
374        self.assertEqual(
375            self.student['studycourse']['100']['COURSE1'].ca, 22)
376
377    def test_scores_previous_session(self):
378        # lecturers can download a CSV file to set values.
379        self.login_as_lecturer()
380        self.student['studycourse']['100']['COURSE1'].score = 55
381        self.browser.open(self.edit_prev_scores_url)
382        self.assertTrue('No student found' in self.browser.contents)
383        configuration = createObject('waeup.SessionConfiguration')
384        configuration.academic_session = 2003
385        self.app['configuration'].addSessionConfiguration(configuration)
386        self.app['configuration']['2003'].score_editing_enabled = ['ug_ft']
387        self.student['studycourse']['100'].level_session = 2003
388        notify(grok.ObjectModifiedEvent(self.student['studycourse']['100']['COURSE1']))
389        self.browser.open(self.edit_prev_scores_url)
390        self.browser.getLink("Download csv file").click()
391        self.assertEqual(self.browser.headers['Status'], '200 Ok')
392        self.assertEqual(self.browser.headers['Content-Type'],
393                         'text/csv; charset=UTF-8')
394        self.assertEqual(self.browser.contents,
395            'matric_number,student_id,display_fullname,'
396            'depcode,faccode,level,code,level_session,ca,score,'
397            'total_score,grade\r\n234,E1000000,"TESTER, Anna",dep1,fac1,'
398            '100,COURSE1,2003,,55,,\r\n')
399        self.browser.open(self.edit_prev_scores_url)
400        upload_ctrl = self.browser.getControl(name='uploadfile:file')
401        upload_file = StringIO(UPLOAD_CSV_TEMPLATE % ('65','22'))
402        upload_ctrl.add_file(upload_file, 'text/csv', 'myscores.csv')
403        self.browser.getControl("Update editable scores from").click()
404        # value changed
405        self.assertEqual(
406            self.student['studycourse']['100']['COURSE1'].score, 65)
407        self.assertEqual(
408            self.student['studycourse']['100']['COURSE1'].ca, 22)
409
410    def test_lecturers_can_download_course_tickets(self):
411        # A course ticket slip can be downloaded
412        self.login_as_lecturer()
413        self.student['studycourse']['100']['COURSE1'].score = 55
414        self.student['studycourse']['100']['COURSE1'].ca = 11
415        self.app['configuration']['2004'].score_editing_enabled = ['ug_ft']
416        pdf_url = '%s/coursetickets.pdf' % self.course_url
417        self.browser.open(pdf_url)
418        self.assertEqual(self.browser.headers['Status'], '200 Ok')
419        self.assertEqual(
420            self.browser.headers['Content-Type'], 'application/pdf')
421        path = os.path.join(samples_dir(), 'coursetickets.pdf')
422        open(path, 'wb').write(self.browser.contents)
423        print "Sample PDF coursetickets.pdf written to %s" % path
424
425    def test_lecturers_do_only_see_selected_students(self):
426        # A course ticket slip can be downloaded
427        self.login_as_lecturer()
428        self.student['studycourse']['100']['COURSE1'].score = 55
429        self.student['studycourse']['100']['COURSE1'].ca = 11
430        self.browser.open(self.edit_scores_url)
431        self.assertTrue('No student found' in self.browser.contents)
432        pdf_url = '%s/coursetickets.pdf' % self.course_url
433        self.browser.open(pdf_url)
434        self.assertEqual(self.browser.headers['Status'], '200 Ok')
435        self.assertEqual(
436            self.browser.headers['Content-Type'], 'application/pdf')
437        path = os.path.join(samples_dir(), 'coursetickets_filtered.pdf')
438        open(path, 'wb').write(self.browser.contents)
439        print "Sample PDF coursetickets_filtered.pdf written to %s" % path
440        self.app['configuration']['2004'].score_editing_enabled = ['ug_ft']
441        self.browser.open(self.edit_scores_url)
442        self.assertFalse('No student found' in self.browser.contents)
443        self.assertTrue('TESTER, Anna' in self.browser.contents)
444
445    def test_transcripts(self):
446        studylevel = createObject(u'waeup.StudentStudyLevel')
447        studylevel.level = 100
448        studylevel.level_session = 2005
449        self.student['studycourse'].entry_mode = 'ug_ft'
450        self.student['studycourse'].addStudentStudyLevel(
451            self.certificate, studylevel)
452        studylevel2 = createObject(u'waeup.StudentStudyLevel')
453        studylevel2.level = 200
454        studylevel2.level_session = 2006
455        self.student['studycourse']['100']['COURSE1'].score = 33 # no carry-over!
456        self.student['studycourse']['100']['COURSE1'].ca = 22
457        self.student['studycourse'].addStudentStudyLevel(
458            self.certificate, studylevel2)
459        # Add second course (COURSE has been added automatically)
460        courseticket = createObject('waeup.CourseTicket')
461        courseticket.code = 'ANYCODE'
462        courseticket.title = u'Any TITLE'
463        courseticket.credits = 13
464        courseticket.score = 55
465        courseticket.ca = 11
466        courseticket.semester = 1
467        courseticket.dcode = u'ANYDCODE'
468        courseticket.fcode = u'ANYFCODE'
469        self.student['studycourse']['200']['COURSE2'] = courseticket
470        self.assertEqual(self.student['studycourse']['100'].gpa_params_rectified[0], 3.0)
471        self.assertEqual(self.student['studycourse']['200'].gpa_params_rectified[0], 4.0)
472        # Get transcript data
473        td = self.student['studycourse'].getTranscriptData()
474        self.assertEqual(td[0][0]['level_key'], '100')
475        self.assertEqual(td[0][0]['sgpa'], 3.0)
476        self.assertEqual(td[0][0]['level'].level, 100)
477        self.assertEqual(td[0][0]['level'].level_session, 2005)
478        self.assertEqual(td[0][0]['tickets_1'][0].code, 'COURSE1')
479        self.assertEqual(td[0][1]['level_key'], '200')
480        self.assertEqual(td[0][1]['sgpa'], 4.0)
481        self.assertEqual(td[0][1]['level'].level, 200)
482        self.assertEqual(td[0][1]['level'].level_session, 2006)
483        self.assertEqual(td[0][1]['tickets_1'][0].code, 'ANYCODE')
484        self.assertEqual(td[1], 3.5652173913043477)
485        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
486        self.browser.open(self.student_path + '/studycourse/transcript')
487        self.assertEqual(self.browser.headers['Status'], '200 Ok')
488        self.assertTrue('Transcript' in self.browser.contents)
489        # Officers can open the pdf transcript
490        self.browser.open(self.student_path + '/studycourse/transcript.pdf')
491        self.assertEqual(self.browser.headers['Status'], '200 Ok')
492        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
493        path = os.path.join(samples_dir(), 'transcript.pdf')
494        open(path, 'wb').write(self.browser.contents)
495        print "Sample PDF transcript.pdf written to %s" % path
496
497    def test_payment_disabled(self):
498        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
499        self.browser.open(self.payments_path)
500        IWorkflowState(self.student).setState('cleared')
501        self.browser.getLink("Add current session payment ticket").click()
502        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
503        self.browser.getControl("Create ticket").click()
504        self.assertMatches('...ticket created...', self.browser.contents)
505        self.app['configuration']['2004'].payment_disabled = ['sf_all']
506        self.browser.getLink("Add current session payment ticket").click()
507        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
508        self.browser.getControl("Create ticket").click()
509        self.assertMatches('...This category of payments has been disabled...',
510                           self.browser.contents)
511
512        self.app['configuration']['2004'].payment_disabled = ['sf_ug_pt']
513        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
514        self.browser.getControl("Create ticket").click()
515        self.assertMatches('...ticket created...', self.browser.contents)
516        self.certificate.study_mode = 'ug_pt'
517        self.browser.getLink("Add current session payment ticket").click()
518        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
519        self.browser.getControl("Create ticket").click()
520        self.assertMatches('...This category of payments has been disabled...',
521                           self.browser.contents)
522
523        self.app['configuration']['2004'].payment_disabled = ['sf_pg']
524        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
525        self.browser.getControl("Create ticket").click()
526        self.assertMatches('...ticket created...', self.browser.contents)
527        self.certificate.study_mode = 'special_pg_ft'
528        self.browser.getLink("Add current session payment ticket").click()
529        self.browser.getControl(name="form.p_category").value = ['schoolfee']
530        self.browser.getControl("Create ticket").click()
531        self.assertMatches('...This category of payments has been disabled...',
532                           self.browser.contents)
533        return
534
535class StudentUITests(StudentsFullSetup):
536    """Tests for customized student class views and pages
537    """
538
539    layer = FunctionalLayer
540
541    def setUp(self):
542        super(StudentUITests, self).setUp()
543
544        bedticket = BedTicket()
545        bedticket.booking_session = 2004
546        bedticket.bed_type = u'any bed type'
547        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
548        bedticket.bed_coordinates = u'My bed coordinates'
549        self.student['accommodation'].addBedTicket(bedticket)
550
551    def test_maintenance_fee_payment(self):
552        self.certificate.study_mode = 'ug_ft'
553        self.student['studycourse'].entry_session = 2013
554        self.student.nationality = u'NG'
555        IWorkflowState(self.student).setState('cleared')
556        self.browser.open(self.login_path)
557        self.browser.getControl(name="form.login").value = self.student_id
558        self.browser.getControl(name="form.password").value = 'spwd'
559        self.browser.getControl("Login").click()
560        self.browser.open(self.student_path + '/payments')
561        self.browser.getLink("Add current session payment ticket").click()
562        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
563        self.browser.getControl("Create ticket").click()
564        self.assertTrue('ticket created' in self.browser.contents)
565        value = self.student['payments'].keys()[0]
566        self.browser.getLink(value).click()
567        self.assertTrue('<span>My bed coordinates</span>' in self.browser.contents)
568        self.assertEqual(self.student['payments'][value].amount_auth, 876.0)
569        return
570
571    def test_student_schoolfee_payments(self):
572        configuration_1 = createObject('waeup.SessionConfiguration')
573        configuration_1.academic_session = 2016
574        self.app['configuration'].addSessionConfiguration(configuration_1)
575        self.certificate.study_mode = 'ug_ft'
576        self.student['studycourse'].entry_session = 2016
577        self.student['studycourse'].current_session = 2016
578        self.student['studycourse'].entry_mode = 'ug_ft'
579        self.student['studycourse'].certificate.school_fee_1 = 50250.0
580        self.app['configuration']['2016'].union_fee = 1250.0
581        self.app['configuration']['2016'].welfare_fee = 750.0
582        self.app['configuration']['2016'].id_card_fee = 350.0
583        self.student.nationality = u'NG'
584        # Login
585        IWorkflowState(self.student).setState('cleared')
586        self.browser.open(self.login_path)
587        self.browser.getControl(name="form.login").value = self.student_id
588        self.browser.getControl(name="form.password").value = 'spwd'
589        self.browser.getControl("Login").click()
590        # Test school fee payments
591        self.browser.open(self.student_path + '/payments')
592        self.browser.getLink("Add current session payment ticket").click()
593        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
594        self.browser.getControl("Create ticket").click()
595        self.assertTrue('ticket created' in self.browser.contents)
596        value = self.student['payments'].keys()[0]
597        self.browser.getLink(value).click()
598        self.assertTrue('Amount Authorized' in self.browser.contents)
599        # 50250 + 1000 + 500 + 100 = 51850
600        self.assertEqual(self.student['payments'][value].amount_auth, 51850.0)
601        self.browser.open(self.browser.url + '/payment_slip.pdf')
602        self.assertEqual(self.browser.headers['Status'], '200 Ok')
603        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
604        path = os.path.join(samples_dir(), 'payment_slip.pdf')
605        open(path, 'wb').write(self.browser.contents)
606        print "Sample PDF payment_slip.pdf written to %s" % path
607        # Another school fee payment cannot be added
608        self.student['payments'][value].approve()
609        self.browser.open(self.student_path + '/payments')
610        self.browser.getLink("Add current session payment ticket").click()
611        self.browser.getControl(name="form.p_category").value = ['schoolfee']
612        self.browser.getControl("Create ticket").click()
613        self.assertTrue(
614            'You must choose a payment which includes additional fees'
615            in self.browser.contents)
616        return
617
618    def test_late_registration(self):
619        delta = timedelta(days=10)
620        self.app['configuration'][
621            '2004'].coursereg_deadline = datetime.now(pytz.utc) - delta
622        IWorkflowState(self.student).setState('school fee paid')
623        # Current session is 2004. Here we test course registration for
624        # returning students.
625        self.student['studycourse'].entry_session = 2003
626        self.student['studycourse'].current_session = 2016
627        # Login
628        self.browser.open(self.login_path)
629        self.browser.getControl(name="form.login").value = self.student_id
630        self.browser.getControl(name="form.password").value = 'spwd'
631        self.browser.getControl("Login").click()
632        # Make restitution fee payment
633        # Ivie: The restitution was only for returning students of 2016/2017.
634        # Hence, it is only valid for 2016 payment session returning students.
635        configuration = createObject('waeup.SessionConfiguration')
636        configuration.academic_session = 2016
637        self.app['configuration'].addSessionConfiguration(configuration)
638        self.app['configuration']['2016'].restitution_fee = 9999.0
639        self.browser.open(self.payments_path + '/addop')
640        self.browser.getControl(name="form.p_category").value = ['restitution']
641        self.browser.getControl("Create ticket").click()
642        self.student['payments'].values()[0].approveStudentPayment()
643        # Make late registration fee fee payment
644        self.student['studycourse'].current_session = 2004
645        self.browser.open(self.payments_path + '/addop')
646        self.browser.getControl(name="form.p_category").value = ['late_registration']
647        self.browser.getControl("Create ticket").click()
648        self.assertMatches('...ticket created...',
649                           self.browser.contents)
650        self.browser.getLink("Study Course").click()
651        self.browser.getLink("Add course list").click()
652        self.assertMatches('...Add current level 100 (Year 1)...',
653                           self.browser.contents)
654        self.browser.getControl("Create course list now").click()
655        self.student['studycourse']['100']['COURSE1'].score = 67
656        self.browser.getLink("100").click()
657        # Course results can't be seen
658        self.assertFalse('<td>67</td>' in self.browser.contents)
659        self.browser.getLink("Edit course list").click()
660        self.assertFalse('<td>67</td>' in self.browser.contents)
661        self.browser.getControl("Register course list").click()
662
663        ######################################################
664        # Temporarily disabled ug_ft course registration
665        #self.assertTrue('Please check back later'
666        #    in self.browser.contents)
667        #return
668        ######################################################
669
670        self.assertTrue('Course registration has ended. Please pay' in self.browser.contents)
671        self.student['payments'].values()[1].approve()
672        self.browser.getControl("Register course list").click()
673        self.assertTrue('Course list has been registered' in self.browser.contents)
674        self.assertEqual(self.student.state, 'courses registered')
675        # Reset student and check if fresh students are always allowed to
676        # register courses.
677        self.student['studycourse'].entry_session = 2004
678        del self.student['payments'][self.student['payments'].keys()[1]]
679        IWorkflowState(self.student).setState('school fee paid')
680        self.browser.open(self.studycourse_path + '/100/edit')
681        self.browser.getControl("Register course list").click()
682        self.assertTrue('Course list has been registered' in self.browser.contents)
683        return
684
685
686    def deactivated_test_student_course_registration(self):
687        # Add more courses
688        self.course2 = createObject('waeup.Course')
689        self.course2.code = 'COURSE2'
690        self.course2.semester = 2
691        self.course2.credits = 10
692        self.course2.passmark = 40
693        self.app['faculties']['fac1']['dep1'].courses.addCourse(
694            self.course2)
695        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
696            self.course2, level=100)
697        self.course3 = createObject('waeup.Course')
698        self.course3.code = 'COURSE3'
699        self.course3.semester = 3
700        self.course3.credits = 10
701        self.course3.passmark = 40
702        self.app['faculties']['fac1']['dep1'].courses.addCourse(
703            self.course3)
704        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
705            self.course3, level=100)
706
707        # Login as student
708        self.browser.open(self.login_path)
709        IWorkflowState(self.student).setState('school fee paid')
710        self.browser.open(self.login_path)
711        self.browser.getControl(name="form.login").value = self.student_id
712        self.browser.getControl(name="form.password").value = 'spwd'
713        self.browser.getControl("Login").click()
714        # Students can add the current study level
715        self.browser.getLink("Study Course").click()
716        self.browser.getLink("Add course list").click()
717        self.assertMatches('...Add current level 100 (Year 1)...',
718                           self.browser.contents)
719        self.browser.getControl("Create course list now").click()
720        # Student has not paid second instalment, therefore a level
721        # with two course ticket was created (semester 1 and combined)
722        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
723        self.browser.getLink("100").click()
724        self.browser.getLink("Edit course list").click()
725        self.browser.getControl("Add course ticket").click()
726        # Student can't add second semester course
727        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
728        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
729        self.assertFalse('<option value="COURSE2">' in self.browser.contents)
730
731        # Let's remove level and see what happens after 2nd instalment payment
732        del(self.student['studycourse']['100'])
733        payment2 = createObject('waeup.StudentOnlinePayment')
734        payment2.p_category = u'schoolfee_2'
735        payment2.p_session = self.student.current_session
736        self.student['payments']['anykey'] = payment2
737        self.browser.open(self.studycourse_path)
738        self.browser.getLink("Add course list").click()
739        self.browser.getControl("Create course list now").click()
740        # Still only 2 tickets have been created since payment ticket
741        # was not paid
742        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
743        payment2.p_state = u'paid'
744        del(self.student['studycourse']['100'])
745        self.browser.open(self.studycourse_path)
746        self.browser.getLink("Add course list").click()
747        self.browser.getControl("Create course list now").click()
748        # Now 2nd semester course has been added
749        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
750        # Student can add second semester course
751        self.browser.getLink("100").click()
752        self.browser.getLink("Edit course list").click()
753        self.browser.getControl("Add course ticket").click()
754        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
755        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
756        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
757        return
758
759    def test_set_matric_number(self):
760        #payment = createObject('waeup.StudentOnlinePayment')
761        #payment.p_category = u'concessional'
762        #payment.p_id = u'anyid'
763        #payment.p_state = u'paid'
764        #self.student['payments']['anykey'] = payment
765        # Login as student
766        self.browser.open(self.login_path)
767        IWorkflowState(self.student).setState('school fee paid')
768        self.browser.open(self.login_path)
769        self.browser.getControl(name="form.login").value = self.student_id
770        self.browser.getControl(name="form.password").value = 'spwd'
771        self.browser.getControl("Login").click()
772        self.assertRaises(
773            LinkNotFoundError,
774            self.browser.getLink, 'Get Matriculation Number')
775        self.student.matric_number = None
776        site = grok.getSite()
777        site['configuration'].next_matric_integer = 1
778        self.student['studycourse'].certificate.study_mode = 'ug_pt'
779        self.browser.open(self.student_path)
780        self.assertRaises(
781            LinkNotFoundError,
782            self.browser.getLink, 'Download matriculation number slip')
783        self.browser.getLink("Get Matriculation Number").click()
784        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
785            in self.browser.contents)
786        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
787        self.assertRaises(
788            LinkNotFoundError,
789            self.browser.getLink, 'Get Matriculation Number')
790        # Setting matric number is logged.
791        logfile = os.path.join(
792            self.app['datacenter'].storage, 'logs', 'students.log')
793        logcontent = open(logfile).read()
794        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
795                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
796        # Matric Number Slip can be downloaded
797        self.browser.getLink("Download matriculation number slip").click()
798        self.assertEqual(self.browser.headers['Status'], '200 Ok')
799        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
800        path = os.path.join(samples_dir(), 'matric_number_slip.pdf')
801        open(path, 'wb').write(self.browser.contents)
802        print "Sample PDF matric_number_slip.pdf written to %s" % path
803        return
804
805    def test_personal_data_slip(self):
806        # Login as student
807        self.browser.open(self.login_path)
808        IWorkflowState(self.student).setState('school fee paid')
809        self.browser.open(self.login_path)
810        self.browser.getControl(name="form.login").value = self.student_id
811        self.browser.getControl(name="form.password").value = 'spwd'
812        self.browser.getControl("Login").click()
813        self.browser.getLink("Personal Data").click()
814        self.assertRaises(
815            LinkNotFoundError,
816            self.browser.getLink, 'Download personal data slip')
817        self.student.father_name = u'Rudolf'
818        self.browser.open(self.personal_path)
819        self.browser.getLink("Download personal data slip").click()
820        self.assertEqual(self.browser.headers['Status'], '200 Ok')
821        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
822        path = os.path.join(samples_dir(), 'personal_data_slip.pdf')
823        open(path, 'wb').write(self.browser.contents)
824        print "Sample PDF personal_data_slip.pdf written to %s" % path
825        return
826
827    def test_student_course_registration(self):
828        IWorkflowState(self.student).setState('school fee paid')
829        self.browser.open(self.login_path)
830        self.browser.getControl(name="form.login").value = self.student_id
831        self.browser.getControl(name="form.password").value = 'spwd'
832        self.browser.getControl("Login").click()
833        # Now students can add the current study level
834        self.browser.getLink("Study Course").click()
835        self.browser.getLink("Add course list").click()
836        self.assertMatches('...Add current level 100 (Year 1)...',
837                           self.browser.contents)
838        self.browser.getControl("Create course list now").click()
839        # Students can't open the customized pdf course registration slip
840        self.browser.open(
841            self.student_path + '/studycourse/100/course_registration_slip.pdf')
842        self.assertTrue('Forbidden' in self.browser.contents)
843        # They can open slips from the previous session ...
844        self.student['studycourse'].current_level = 200
845        self.browser.open(self.student_path + '/studycourse/100')
846        self.browser.getLink("Download course registration slip").click()
847        self.assertEqual(self.browser.headers['Status'], '200 Ok')
848        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
849        # or if they have registered their course list
850        self.student['studycourse'].current_level = 200
851        IWorkflowState(self.student).setState('courses registered')
852        self.browser.open(self.student_path + '/studycourse/100')
853        self.browser.getLink("Download course registration slip").click()
854        self.assertEqual(self.browser.headers['Status'], '200 Ok')
855        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
856        path = os.path.join(samples_dir(), 'ft_course_registration_slip.pdf')
857        open(path, 'wb').write(self.browser.contents)
858        print "Sample PDF ft_course_registration_slip.pdf written to %s" % path
859
860        self.certificate.study_mode = 'ug_pt'
861        self.browser.open(self.student_path + '/studycourse/100')
862        self.browser.getLink("Download course registration slip").click()
863        self.assertEqual(self.browser.headers['Status'], '200 Ok')
864        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
865        path = os.path.join(samples_dir(), 'pt_course_registration_slip.pdf')
866        open(path, 'wb').write(self.browser.contents)
867        print "Sample PDF pt_course_registration_slip.pdf written to %s" % path
868
869        self.certificate.study_mode = 'special_pg_ft'
870        self.student.matric_number = u'AAU/SPS/FLW/LAW/15/PHD/09504'
871        self.browser.open(self.student_path + '/studycourse/100')
872        self.browser.getLink("Download course registration slip").click()
873        self.assertEqual(self.browser.headers['Status'], '200 Ok')
874        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
875        path = os.path.join(samples_dir(), 'pg_course_registration_slip.pdf')
876        open(path, 'wb').write(self.browser.contents)
877        print "Sample PDF pg_course_registration_slip.pdf written to %s" % path
878
879        # Students cant' view scores, cas and grades.
880        self.browser.open(self.student_path + '/studycourse/100')
881        self.assertFalse('Score' in self.browser.contents)
882        self.assertFalse('CA' in self.browser.contents)
883        self.assertFalse('Grade' in self.browser.contents)
884        self.browser.getLink("COURSE1").click()
885        self.browser.open(self.student_path + '/studycourse/100')
886        self.assertFalse('Score' in self.browser.contents)
887        self.assertFalse('CA' in self.browser.contents)
888        self.assertFalse('Grade' in self.browser.contents)
889
890    def test_student_2nd_semester_course_registration(self):
891        IWorkflowState(self.student).setState('school fee paid')
892        self.student['studycourse'].entry_session = 2015
893        self.course.semester = 2
894        self.browser.open(self.login_path)
895        self.browser.getControl(name="form.login").value = self.student_id
896        self.browser.getControl(name="form.password").value = 'spwd'
897        self.browser.getControl("Login").click()
898        self.browser.getLink("Study Course").click()
899        self.browser.getLink("Add course list").click()
900        self.browser.getControl("Create course list now").click()
901        self.assertFalse('COURSE1' in self.browser.contents)
902        # 2nd semester tickets can't be added manually
903        self.browser.getLink("Edit course list").click()
904        self.browser.getLink("here").click()
905        self.browser.getControl(name="form.course").value = ['COURSE1']
906        self.browser.getControl("Add course ticket").click()
907        self.assertTrue(
908            'COURSE1 is a 2nd semester course which can only '
909            'be added if school fees have been fully paid.'
910            in self.browser.contents)
911        # 2nd instalment has to be paid first
912        self.certificate.school_fee_3 = 678.0
913        self.browser.open(self.payments_path + '/addop')
914        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
915        self.browser.getControl("Create ticket").click()
916        self.student['payments'].values()[0].approve()
917        self.browser.open(self.studycourse_path + '/100/ctadd')
918        self.browser.getControl(name="form.course").value = ['COURSE1']
919        self.browser.getControl("Add course ticket").click()
920        self.assertTrue('Successfully added COURSE1' in self.browser.contents)
921        return
922
923    def test_student_GST_registration(self):
924        configuration_1 = createObject('waeup.SessionConfiguration')
925        configuration_1.academic_session = 2016
926        configuration_1.gst_registration_1_fee = 3333.0
927        configuration_1.gst_text_book_1_fee = 4444.0
928        configuration_1.gst_text_book_0_fee = 2222.0
929        self.app['configuration'].addSessionConfiguration(configuration_1)
930        course = createObject('waeup.Course')
931        course.code = 'GST101'
932        course.semester = 1
933        course.credits = 10
934        course.passmark = 40
935        self.app['faculties']['fac1']['dep1'].courses.addCourse(
936            course)
937        self.app['faculties']['fac1']['dep1'].certificates[
938            'CERT1'].addCertCourse(course, level=100)
939        IWorkflowState(self.student).setState('school fee paid')
940        self.student['studycourse'].entry_session = 2016
941        self.student['studycourse'].current_session = 2016
942        self.course.semester = 2
943        self.browser.open(self.login_path)
944        self.browser.getControl(name="form.login").value = self.student_id
945        self.browser.getControl(name="form.password").value = 'spwd'
946        self.browser.getControl("Login").click()
947        self.browser.getLink("Study Course").click()
948        self.browser.getLink("Add course list").click()
949        self.browser.getControl("Create course list now").click()
950        self.assertFalse('GST101' in self.browser.contents)
951        # GST101 tickets can't be added manually
952        self.browser.getLink("Edit course list").click()
953        self.browser.getLink("here").click()
954        self.browser.getControl(name="form.course").value = ['GST101']
955        self.browser.getControl("Add course ticket").click()
956        self.assertTrue(
957            'GST101 can only be added if both registration fee and text'
958            in self.browser.contents)
959        # GST fees have to be paid first
960        self.browser.open(self.payments_path + '/addop')
961        self.browser.getControl(name="form.p_category").value = ['gst_registration_1']
962        self.browser.getControl("Create ticket").click()
963        self.student['payments'].values()[0].approve()
964        self.browser.open(self.studycourse_path + '/100/ctadd')
965        self.browser.getControl(name="form.course").value = ['GST101']
966        self.browser.getControl("Add course ticket").click()
967        self.assertTrue(
968            'GST101 can only be added if both registration fee and text'
969            in self.browser.contents)
970        self.browser.open(self.payments_path + '/addop')
971        self.browser.getControl(name="form.p_category").value = ['gst_text_book_0']
972        self.browser.getControl("Create ticket").click()
973        self.student['payments'].values()[1].approve()
974        self.browser.open(self.studycourse_path + '/100/ctadd')
975        self.browser.getControl(name="form.course").value = ['GST101']
976        self.browser.getControl("Add course ticket").click()
977        self.assertTrue('Successfully added GST101' in self.browser.contents)
978        return
979
980    def test_course_registration_forbidden(self):
981        IWorkflowState(self.student).setState('school fee paid')
982        self.student['studycourse'].entry_session = 2016
983        self.student['studycourse'].current_session = 2016
984        self.browser.open(self.login_path)
985        self.browser.getControl(name="form.login").value = self.student_id
986        self.browser.getControl(name="form.password").value = 'spwd'
987        self.browser.getControl("Login").click()
988        self.browser.getLink("Study Course").click()
989        self.browser.getLink("Add course list").click()
990        self.browser.getControl("Create course list now").click()
991        self.browser.getLink("Edit course list").click()
992        self.browser.getControl("Register course list").click()
993        #self.assertTrue('Please pay faculty and departmental dues first'
994        #    in self.browser.contents)
995        #configuration_1 = createObject('waeup.SessionConfiguration')
996        #configuration_1.academic_session = 2016
997        #configuration_1.fac_dep_fee = 9999.0
998        #self.app['configuration'].addSessionConfiguration(configuration_1)
999        #self.browser.open(self.payments_path + '/addop')
1000        #self.browser.getControl(name="form.p_category").value = ['fac_dep']
1001        #self.browser.getControl("Create ticket").click()
1002        #self.student['payments'].values()[0].approveStudentPayment()
1003        #self.browser.open(self.studycourse_path + '/100/edit')
1004        #self.browser.getControl("Register course list").click()
1005
1006        ######################################################
1007        # Temporarily disabled ug_ft course registration
1008        #self.assertTrue('Please check back later'
1009        #    in self.browser.contents)
1010        #return
1011        ######################################################
1012
1013        self.assertTrue('Course list has been registered'
1014            in self.browser.contents)
1015        return
1016
1017    def test_course_registration_forbidden_2(self):
1018        IWorkflowState(self.student).setState('school fee paid')
1019        self.student['studycourse'].entry_session = 2004
1020        self.student['studycourse'].current_session = 2016
1021        self.browser.open(self.login_path)
1022        self.browser.getControl(name="form.login").value = self.student_id
1023        self.browser.getControl(name="form.password").value = 'spwd'
1024        self.browser.getControl("Login").click()
1025        self.browser.getLink("Study Course").click()
1026        self.browser.getLink("Add course list").click()
1027        self.browser.getControl("Create course list now").click()
1028        self.browser.getLink("Edit course list").click()
1029        self.browser.getControl("Register course list").click()
1030
1031        ######################################################
1032        # Temporarily disabled ug_ft course registration
1033        #self.assertTrue('Please check back later'
1034        #    in self.browser.contents)
1035        #return
1036        ######################################################
1037
1038        self.assertTrue('Please pay restitution fee first'
1039            in self.browser.contents)
1040        configuration = createObject('waeup.SessionConfiguration')
1041        configuration.academic_session = 2016
1042        self.app['configuration'].addSessionConfiguration(configuration)
1043        self.app['configuration']['2016'].restitution_fee = 9999.0
1044        self.browser.open(self.payments_path + '/addop')
1045        self.browser.getControl(name="form.p_category").value = ['restitution']
1046        self.browser.getControl("Create ticket").click()
1047        self.student['payments'].values()[0].approveStudentPayment()
1048        self.browser.open(self.studycourse_path + '/100/edit')
1049        self.browser.getControl("Register course list").click()
1050        self.assertTrue('Course list has been registered'
1051            in self.browser.contents)
1052        return
1053
1054    def test_student_access_course_results(self):
1055        IWorkflowState(self.student).setState('school fee paid')
1056        self.student['studycourse'].entry_session = 2004
1057        self.student['studycourse'].current_session = 2004
1058        self.browser.open(self.login_path)
1059        self.browser.getControl(name="form.login").value = self.student_id
1060        self.browser.getControl(name="form.password").value = 'spwd'
1061        self.browser.getControl("Login").click()
1062        self.browser.getLink("Study Course").click()
1063        self.browser.getLink("Add course list").click()
1064        self.browser.getControl("Create course list now").click()
1065        self.assertFalse('Score' in self.browser.contents)
1066        IWorkflowState(self.student).setState('returning')
1067        self.browser.open(self.studycourse_path + '/100')
1068        self.assertFalse('Score' in self.browser.contents)
1069        self.app['configuration']['2004'].show_results = ['ug_ft']
1070        self.browser.open(self.studycourse_path + '/100')
1071        self.assertTrue('Score' in self.browser.contents)
1072        return
1073
1074    def test_student_clearance(self):
1075        # Student cant login if their password is not set
1076        IWorkflowInfo(self.student).fireTransition('admit')
1077        self.browser.open(self.login_path)
1078        self.browser.getControl(name="form.login").value = self.student_id
1079        self.browser.getControl(name="form.password").value = 'spwd'
1080        self.browser.getControl("Login").click()
1081        self.assertMatches(
1082            '...You logged in...', self.browser.contents)
1083        # Admitted student can upload a passport picture
1084        self.browser.open(self.student_path + '/change_portrait')
1085        ctrl = self.browser.getControl(name='passportuploadedit')
1086        file_obj = open(SAMPLE_IMAGE, 'rb')
1087        file_ctrl = ctrl.mech_control
1088        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
1089        self.browser.getControl(
1090            name='upload_passportuploadedit').click()
1091        self.assertTrue(
1092            'src="http://localhost/app/students/E1000000/passport.jpg"'
1093            in self.browser.contents)
1094        # Student is redirected to the personal data form because
1095        # personal data form is not properly filled.
1096        self.browser.open(self.student_path + '/start_clearance')
1097        self.assertMatches('...Personal data form is not properly filled...',
1098                           self.browser.contents)
1099        self.assertEqual(self.browser.url, self.student_path + '/edit_personal')
1100        self.student.father_name = u'Rudolf'
1101        self.browser.open(self.student_path + '/start_clearance')
1102        self.assertMatches(
1103            '...<h1 class="kofa-content-label">Start clearance</h1>...',
1104            self.browser.contents)
1105
1106    def test_student_accommodation(self):
1107        del self.student['accommodation']['2004']
1108        self.student['studycourse'].certificate.study_mode = 'dp_ft'
1109        # All beds can be assigned
1110        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
1111        bed1.bed_type = u'regular_male_all'
1112        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
1113        bed2.bed_type = u'regular_female_all'
1114        notify(grok.ObjectModifiedEvent(bed1))
1115        notify(grok.ObjectModifiedEvent(bed2))
1116        # Login
1117        self.browser.open(self.login_path)
1118        self.browser.getControl(name="form.login").value = self.student_id
1119        self.browser.getControl(name="form.password").value = 'spwd'
1120        self.browser.getControl("Login").click()
1121        # Students can book accommodation without AC ...
1122        self.browser.open(self.acco_path)
1123        IWorkflowInfo(self.student).fireTransition('admit')
1124        self.browser.getControl("Book accommodation").click()
1125        self.assertTrue(
1126            'You are not eligible to book accommodation.'
1127            in self.browser.contents)
1128        self.student['studycourse'].certificate.study_mode = 'ug_ft'
1129        self.app['hostels'].accommodation_states = [PAID]
1130        self.browser.getControl("Book accommodation").click()
1131        self.assertTrue(
1132            'You are in the wrong registration state.'
1133            in self.browser.contents)
1134        IWorkflowState(self.student).setState(PAID)
1135        self.browser.getControl("Book accommodation").click()
1136        self.assertFalse('Activation Code:' in self.browser.contents)
1137        self.browser.getControl("Create bed ticket").click()
1138        # Bed is randomly selected but, since there is only
1139        # one bed for this student, we know that
1140        self.assertEqual(self.student['accommodation']['2004'].bed_coordinates,
1141            'Hall 1, Block A, Room 101, Bed A (regular_male_all)')
1142        # Only the hall name is displayed
1143        self.assertEqual(self.student[
1144            'accommodation']['2004'].display_coordinates,
1145            'Hall 1')
1146        self.assertFalse('Hall 1, Block A, Room 101, Bed A'
1147            in self.browser.contents)
1148        self.assertTrue('<td>Hall 1</td>'
1149            in self.browser.contents)
1150        return
1151
1152    def test_handle_courses_by_lecturer(self):
1153        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
1154        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
1155        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
1156        # Add course ticket
1157        studylevel = createObject(u'waeup.StudentStudyLevel')
1158        studylevel.level = 100
1159        studylevel.level_session = 2004
1160        self.student['studycourse'].addStudentStudyLevel(
1161            self.certificate, studylevel)
1162        # Assign local Lecturer role for a certificate.
1163        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
1164        prmlocal = IPrincipalRoleManager(course)
1165        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
1166        notify(LocalRoleSetEvent(
1167            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
1168        # Login as lecturer.
1169        self.browser.open(self.login_path)
1170        self.browser.getControl(name="form.login").value = 'mrslecturer'
1171        self.browser.getControl(name="form.password").value = 'mrslecturersecret'
1172        self.browser.getControl("Login").click()
1173        self.browser.getLink("My Courses").click()
1174        self.browser.getLink("COURSE1").click()
1175        # Course results can be batch edited via the edit_courses view.
1176        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
1177        self.app['configuration'].current_academic_session = 2004
1178        self.app['configuration']['2004'].score_editing_enabled = ['ug_ft']
1179        IWorkflowState(self.student).setState('courses validated')
1180        self.browser.open(
1181            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
1182        self.assertTrue(
1183            'input type="text" name="scores:list"'
1184            in self.browser.contents)
1185        self.browser.getControl(name="scores:list", index=0).value = '55'
1186        self.browser.getControl(name="cas:list", index=0).value = '22'
1187        self.browser.getControl("Update scores from").click()
1188        # New score and ca has been set.
1189        self.assertEqual(
1190            self.student['studycourse']['100']['COURSE1'].score, 55)
1191        self.assertEqual(
1192            self.student['studycourse']['100']['COURSE1'].ca, 22)
1193        # Score editing has been logged.
1194        logfile = os.path.join(
1195            self.app['datacenter'].storage, 'logs', 'students.log')
1196        logcontent = open(logfile).read()
1197        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
1198                        'E1000000 100/COURSE1 score updated (55)' in logcontent)
1199        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
1200                        'E1000000 100/COURSE1 ca updated (22)' in logcontent)
1201        # Non-integer scores won't be accepted.
1202        self.browser.open(
1203            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
1204        self.assertTrue('value="55" />' in self.browser.contents)
1205        self.browser.getControl(name="scores:list", index=0).value = 'abc'
1206        self.browser.getControl("Update scores").click()
1207        self.assertTrue('Error: Score(s) and CA(s) of TESTER, Anna have not be updated.'
1208            in self.browser.contents)
1209        # Scores can be removed.
1210        self.browser.open(
1211            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
1212        self.browser.getControl(name="scores:list", index=0).value = ''
1213        self.browser.getControl("Update scores").click()
1214        self.assertEqual(
1215            self.student['studycourse']['100']['COURSE1'].score, None)
1216        logcontent = open(logfile).read()
1217        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
1218                        'E1000000 100/COURSE1 score updated (None)' in logcontent)
1219
1220
1221    def disabled_test_student_view_transcript(self):
1222        # Student cant login if their password is not set
1223        IWorkflowInfo(self.student).fireTransition('admit')
1224        self.browser.open(self.login_path)
1225        self.browser.getControl(name="form.login").value = self.student_id
1226        self.browser.getControl(name="form.password").value = 'spwd'
1227        self.browser.getControl("Login").click()
1228        self.assertMatches(
1229            '...You logged in...', self.browser.contents)
1230        # Students can view the transcript
1231        self.browser.open(self.studycourse_path)
1232        self.browser.getLink("Transcript").click()
1233        self.browser.getLink("Academic Transcript").click()
1234        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1235        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1236
1237    def test_alumni_request_pw(self):
1238        # Add an applicants container
1239        applicantscontainer = ApplicantsContainer()
1240        applicantscontainer.code = u'trans2017'
1241        applicantscontainer.prefix = 'trans'
1242        applicantscontainer.year = 2017
1243        applicantscontainer.title = u'This is the trans2017 container'
1244        applicantscontainer.application_category = 'no'
1245        applicantscontainer.mode = 'create'
1246        applicantscontainer.strict_deadline = True
1247        delta = timedelta(days=10)
1248        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
1249        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
1250        self.app['applicants']['trans2017'] = applicantscontainer
1251        self.applicantscontainer = self.app['applicants']['trans2017']
1252        # Student with wrong number can't be found.
1253        # Applicant is redirected to application section.
1254        self.browser.open('http://localhost/app/alumni_requestpw')
1255        self.browser.getControl(name="form.lastname").value = 'Tester'
1256        self.browser.getControl(name="form.number").value = 'anynumber'
1257        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1258        self.browser.getControl("Send login credentials").click()
1259        self.assertTrue('No student record found.'
1260            in self.browser.contents)
1261        self.assertEqual(self.browser.url,
1262            'http://localhost/app/applicants/trans2017/register')
1263
1264    def test_student_course_registration_outstanding(self):
1265        self.course = createObject('waeup.Course')
1266        self.course.code = 'COURSE2'
1267        self.course.semester = 1
1268        self.course.credits = 39
1269        self.course.passmark = 40
1270        self.app['faculties']['fac1']['dep1'].courses.addCourse(
1271            self.course)
1272        IWorkflowState(self.student).setState('school fee paid')
1273        self.browser.open(self.login_path)
1274        self.browser.getControl(name="form.login").value = self.student_id
1275        self.browser.getControl(name="form.password").value = 'spwd'
1276        self.browser.getControl("Login").click()
1277        self.browser.open(self.student_path + '/studycourse/add')
1278        self.browser.getControl("Create course list now").click()
1279        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 1)
1280        self.student['studycourse'].current_level = 200
1281        self.browser.getLink("Study Course").click()
1282        self.browser.getLink("Add course list").click()
1283        self.assertMatches('...Add current level 200 (Year 2)...',
1284                           self.browser.contents)
1285        self.browser.getControl("Create course list now").click()
1286        self.browser.getLink("200").click()
1287        self.browser.getLink("Edit course list").click()
1288        self.browser.getLink("here").click()
1289        self.browser.getControl(name="form.course").value = ['COURSE2']
1290        self.browser.getControl("Add course ticket").click()
1291        # Carryover COURSE1 in level 200 already has 10 credits
1292        self.assertMatches(
1293            '...Maximum credits exceeded...', self.browser.contents)
1294        # If COURSE1 is outstanding, its credits won't be considered
1295        self.student['studycourse']['200']['COURSE1'].outstanding = True
1296        self.browser.getControl("Add course ticket").click()
1297        self.assertMatches(
1298            '...Successfully added COURSE2...', self.browser.contents)
1299        return
1300
1301    def test_examination_schedule_slip(self):
1302        self.student.flash_notice = u'My Examination Date'
1303        self.browser.open(self.login_path)
1304        self.browser.getControl(name="form.login").value = self.student_id
1305        self.browser.getControl(name="form.password").value = 'spwd'
1306        self.browser.getControl("Login").click()
1307        self.browser.getLink("Download examination schedule slip").click()
1308        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1309        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1310        path = os.path.join(samples_dir(), 'examination_schedule_slip.pdf')
1311        open(path, 'wb').write(self.browser.contents)
1312        print "Sample PDF examination_schedule_slip.pdf written to %s" % path
1313        # If flash_notive does not contain exam' the button does not show up.
1314        self.student.flash_notice = u'anything'
1315        self.browser.open(self.student_path)
1316        self.assertFalse('examination schedule slip' in self.browser.contents)
Note: See TracBrowser for help on using the repository browser.