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

Last change on this file since 15835 was 15803, checked in by Henrik Bettermann, 5 years ago

Adjust tests to changes in Nigeria package.

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