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

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

Fix IJMBE payments.

  • Property svn:keywords set to Id
File size: 72.7 KB
Line 
1## $Id: test_browser.py 15997 2020-02-10 10:53:45Z 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-200)/2 + 1250 + 750 - 400 + 200
277        self.assertEqual(self.student['payments'].values()[0].amount_auth, 5033.0)
278        # (6666-200)/2 + 200
279        self.assertEqual(self.student['payments'].values()[1].amount_auth, 3433.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-200)/2 + 1250 + 750 - 400 + 200
312        self.assertEqual(self.student['payments'].values()[2].amount_auth, 4533.0)
313        # (5666-200)/2 + 200
314        self.assertEqual(self.student['payments'].values()[3].amount_auth, 2933.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        # Set Officer 1
522        self.app['faculties']['fac1']['dep1'].officer_1 = u'Transcript Boss'
523        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
524        self.browser.open(self.student_path + '/studycourse/transcript')
525        self.assertEqual(self.browser.headers['Status'], '200 Ok')
526        self.assertTrue('Transcript' in self.browser.contents)
527        # Officers can open the pdf transcript
528        self.browser.open(self.student_path + '/studycourse/transcript.pdf')
529        self.assertEqual(self.browser.headers['Status'], '200 Ok')
530        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
531        path = os.path.join(samples_dir(), 'transcript.pdf')
532        open(path, 'wb').write(self.browser.contents)
533        print "Sample PDF transcript.pdf written to %s" % path
534
535    def test_payment_disabled(self):
536        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
537        self.browser.open(self.payments_path)
538        IWorkflowState(self.student).setState('cleared')
539        self.browser.getLink("Add current session payment ticket").click()
540        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
541        self.browser.getControl("Create ticket").click()
542        self.assertMatches('...ticket created...', self.browser.contents)
543        self.app['configuration']['2004'].payment_disabled = ['sf_all']
544        self.browser.getLink("Add current session payment ticket").click()
545        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
546        self.browser.getControl("Create ticket").click()
547        self.assertMatches('...This category of payments has been disabled...',
548                           self.browser.contents)
549
550        self.app['configuration']['2004'].payment_disabled = ['sf_ug_pt']
551        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
552        self.browser.getControl("Create ticket").click()
553        self.assertMatches('...ticket created...', self.browser.contents)
554        self.certificate.study_mode = 'ug_pt'
555        self.browser.getLink("Add current session payment ticket").click()
556        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
557        self.browser.getControl("Create ticket").click()
558        self.assertMatches('...This category of payments has been disabled...',
559                           self.browser.contents)
560
561        self.app['configuration']['2004'].payment_disabled = ['sf_pg']
562        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
563        self.browser.getControl("Create ticket").click()
564        self.assertMatches('...ticket created...', self.browser.contents)
565        self.certificate.study_mode = 'special_pg_ft'
566        self.browser.getLink("Add current session payment ticket").click()
567        self.browser.getControl(name="form.p_category").value = ['schoolfee']
568        self.browser.getControl("Create ticket").click()
569        self.assertMatches('...This category of payments has been disabled...',
570                           self.browser.contents)
571        return
572
573class StudentUITests(StudentsFullSetup):
574    """Tests for customized student class views and pages
575    """
576
577    layer = FunctionalLayer
578
579    def setUp(self):
580        super(StudentUITests, self).setUp()
581
582        bedticket = BedTicket()
583        bedticket.booking_session = 2004
584        bedticket.bed_type = u'any bed type'
585        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
586        bedticket.bed_coordinates = u'My bed coordinates'
587        self.student['accommodation'].addBedTicket(bedticket)
588
589    def test_maintenance_fee_payment(self):
590        self.certificate.study_mode = 'ug_ft'
591        self.student['studycourse'].entry_session = 2013
592        self.student.nationality = u'NG'
593        IWorkflowState(self.student).setState('cleared')
594        self.browser.open(self.login_path)
595        self.browser.getControl(name="form.login").value = self.student_id
596        self.browser.getControl(name="form.password").value = 'spwd'
597        self.browser.getControl("Login").click()
598        self.browser.open(self.student_path + '/payments')
599        self.browser.getLink("Add current session payment ticket").click()
600        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
601        self.browser.getControl("Create ticket").click()
602        self.assertTrue('ticket created' in self.browser.contents)
603        value = self.student['payments'].keys()[0]
604        self.browser.getLink(value).click()
605        self.assertTrue('<span>My bed coordinates</span>' in self.browser.contents)
606        self.assertEqual(self.student['payments'][value].amount_auth, 876.0)
607        return
608
609    def test_student_schoolfee_payments(self):
610        configuration_1 = createObject('waeup.SessionConfiguration')
611        configuration_1.academic_session = 2018
612        self.app['configuration'].addSessionConfiguration(configuration_1)
613        self.certificate.study_mode = 'ug_ft'
614        self.student['studycourse'].entry_session = 2018
615        self.student['studycourse'].current_session = 2018
616        self.student['studycourse'].entry_mode = 'ug_ft'
617        self.student['studycourse'].certificate.school_fee_1 = 50200.0
618        self.app['configuration']['2018'].union_fee = 1200.0
619        self.app['configuration']['2018'].welfare_fee = 700.0
620        #self.app['configuration']['2017'].id_card_fee = 300.0
621        self.app['configuration']['2018'].sports_fee = 300.0
622        self.app['configuration']['2018'].library_fee = 300.0
623        self.student.nationality = u'NG'
624        # Login
625        IWorkflowState(self.student).setState('cleared')
626        self.browser.open(self.login_path)
627        self.browser.getControl(name="form.login").value = self.student_id
628        self.browser.getControl(name="form.password").value = 'spwd'
629        self.browser.getControl("Login").click()
630        # Test school fee payments
631        self.browser.open(self.student_path + '/payments')
632        self.browser.getLink("Add current session payment ticket").click()
633        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
634        self.browser.getControl("Create ticket").click()
635        self.assertTrue('ticket created' in self.browser.contents)
636        value = self.student['payments'].keys()[0]
637        self.browser.getLink(value).click()
638        self.assertTrue('Amount Authorized' in self.browser.contents)
639        # 50200 + 1200 + 700 + 300 + 300- 800 = 51900
640        self.assertEqual(self.student['payments'][value].amount_auth, 51900.0)
641        self.student['payments'][value].r_company = u'interswitch'
642        self.browser.open(self.browser.url + '/payment_slip.pdf')
643        self.assertEqual(self.browser.headers['Status'], '200 Ok')
644        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
645        path = os.path.join(samples_dir(), 'payment_slip.pdf')
646        open(path, 'wb').write(self.browser.contents)
647        print "Sample PDF payment_slip.pdf written to %s" % path
648        # Another school fee payment cannot be added
649        self.student['payments'][value].approve()
650        self.browser.open(self.student_path + '/payments')
651        self.browser.getLink("Add current session payment ticket").click()
652        self.browser.getControl(name="form.p_category").value = ['schoolfee']
653        self.browser.getControl("Create ticket").click()
654        self.assertTrue(
655            'You must choose a payment which includes additional fees'
656            in self.browser.contents)
657        return
658
659    def test_late_registration(self):
660        delta = timedelta(days=10)
661        self.app['configuration'][
662            '2004'].coursereg_deadline = datetime.now(pytz.utc) - delta
663        IWorkflowState(self.student).setState('school fee paid')
664        # Current session is 2004. Here we test course registration for
665        # returning students.
666        self.student['studycourse'].entry_session = 2003
667        self.student['studycourse'].current_session = 2016
668        # Login
669        self.browser.open(self.login_path)
670        self.browser.getControl(name="form.login").value = self.student_id
671        self.browser.getControl(name="form.password").value = 'spwd'
672        self.browser.getControl("Login").click()
673        # Make restitution fee payment
674        # Ivie: The restitution was only for returning students of 2016/2017.
675        # Hence, it is only valid for 2016 payment session returning students.
676        configuration = createObject('waeup.SessionConfiguration')
677        configuration.academic_session = 2016
678        self.app['configuration'].addSessionConfiguration(configuration)
679        self.app['configuration']['2016'].restitution_fee = 9999.0
680        self.browser.open(self.payments_path + '/addop')
681        self.browser.getControl(name="form.p_category").value = ['restitution']
682        self.browser.getControl("Create ticket").click()
683        self.student['payments'].values()[0].approveStudentPayment()
684        # Make late registration fee payment
685        self.student['studycourse'].current_session = 2004
686        self.browser.open(self.payments_path + '/addop')
687        self.browser.getControl(name="form.p_category").value = ['late_registration']
688        self.browser.getControl("Create ticket").click()
689        self.assertMatches('...ticket created...',
690                           self.browser.contents)
691        self.browser.getLink("Study Course").click()
692        self.browser.getLink("Add course list").click()
693        self.assertMatches('...Add current level 100 (Year 1)...',
694                           self.browser.contents)
695        self.browser.getControl("Create course list now").click()
696        self.student['studycourse']['100']['COURSE1'].score = 67
697        self.browser.getLink("100").click()
698        # Course results can't be seen
699        self.assertFalse('<td>67</td>' in self.browser.contents)
700        self.browser.getLink("Edit course list").click()
701        self.assertFalse('<td>67</td>' in self.browser.contents)
702        self.app['configuration']['2004'].late_registration_fee = 0.0
703        self.browser.getControl("Register course list").click()
704        self.assertTrue('Course registration has been disabled.' in self.browser.contents)
705        self.app['configuration']['2004'].late_registration_fee = 345.0
706        self.browser.getControl("Register course list").click()
707        self.assertTrue('Course registration has ended. Please pay' in self.browser.contents)
708        self.student['payments'].values()[1].approve()
709        self.browser.getControl("Register course list").click()
710        self.assertTrue('Course list has been registered' in self.browser.contents)
711        self.assertEqual(self.student.state, 'courses registered')
712        # Reset student and check if fresh students are always allowed to
713        # register courses.
714        #self.student['studycourse'].entry_session = 2004
715        #del self.student['payments'][self.student['payments'].keys()[1]]
716        #IWorkflowState(self.student).setState('school fee paid')
717        #self.browser.open(self.studycourse_path + '/100/edit')
718        #self.browser.getControl("Register course list").click()
719        #self.assertTrue('Course list has been registered' in self.browser.contents)
720        return
721
722
723    def deactivated_test_student_course_registration(self):
724        # Add more courses
725        self.course2 = createObject('waeup.Course')
726        self.course2.code = 'COURSE2'
727        self.course2.semester = 2
728        self.course2.credits = 10
729        self.course2.passmark = 40
730        self.app['faculties']['fac1']['dep1'].courses.addCourse(
731            self.course2)
732        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
733            self.course2, level=100)
734        self.course3 = createObject('waeup.Course')
735        self.course3.code = 'COURSE3'
736        self.course3.semester = 3
737        self.course3.credits = 10
738        self.course3.passmark = 40
739        self.app['faculties']['fac1']['dep1'].courses.addCourse(
740            self.course3)
741        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
742            self.course3, level=100)
743
744        # Login as student
745        self.browser.open(self.login_path)
746        IWorkflowState(self.student).setState('school fee paid')
747        self.browser.open(self.login_path)
748        self.browser.getControl(name="form.login").value = self.student_id
749        self.browser.getControl(name="form.password").value = 'spwd'
750        self.browser.getControl("Login").click()
751        # Students can add the current study level
752        self.browser.getLink("Study Course").click()
753        self.browser.getLink("Add course list").click()
754        self.assertMatches('...Add current level 100 (Year 1)...',
755                           self.browser.contents)
756        self.browser.getControl("Create course list now").click()
757        # Student has not paid second instalment, therefore a level
758        # with two course ticket was created (semester 1 and combined)
759        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
760        self.browser.getLink("100").click()
761        self.browser.getLink("Edit course list").click()
762        self.browser.getControl("Add course ticket").click()
763        # Student can't add second semester course
764        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
765        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
766        self.assertFalse('<option value="COURSE2">' in self.browser.contents)
767
768        # Let's remove level and see what happens after 2nd instalment payment
769        del(self.student['studycourse']['100'])
770        payment2 = createObject('waeup.StudentOnlinePayment')
771        payment2.p_category = u'schoolfee_2'
772        payment2.p_session = self.student.current_session
773        self.student['payments']['anykey'] = payment2
774        self.browser.open(self.studycourse_path)
775        self.browser.getLink("Add course list").click()
776        self.browser.getControl("Create course list now").click()
777        # Still only 2 tickets have been created since payment ticket
778        # was not paid
779        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
780        payment2.p_state = u'paid'
781        del(self.student['studycourse']['100'])
782        self.browser.open(self.studycourse_path)
783        self.browser.getLink("Add course list").click()
784        self.browser.getControl("Create course list now").click()
785        # Now 2nd semester course has been added
786        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
787        # Student can add second semester course
788        self.browser.getLink("100").click()
789        self.browser.getLink("Edit course list").click()
790        self.browser.getControl("Add course ticket").click()
791        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
792        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
793        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
794        return
795
796    def test_set_matric_number(self):
797        #payment = createObject('waeup.StudentOnlinePayment')
798        #payment.p_category = u'concessional'
799        #payment.p_id = u'anyid'
800        #payment.p_state = u'paid'
801        #self.student['payments']['anykey'] = payment
802        # Login as student
803        self.browser.open(self.login_path)
804        IWorkflowState(self.student).setState('school fee paid')
805        self.browser.open(self.login_path)
806        self.browser.getControl(name="form.login").value = self.student_id
807        self.browser.getControl(name="form.password").value = 'spwd'
808        self.browser.getControl("Login").click()
809        self.assertRaises(
810            LinkNotFoundError,
811            self.browser.getLink, 'Get Matriculation Number')
812        self.student.matric_number = None
813        site = grok.getSite()
814        site['configuration'].next_matric_integer = 1
815        self.student['studycourse'].certificate.study_mode = 'ug_pt'
816        self.browser.open(self.student_path)
817        self.assertRaises(
818            LinkNotFoundError,
819            self.browser.getLink, 'Download matriculation number slip')
820        self.browser.getLink("Get Matriculation Number").click()
821        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
822            in self.browser.contents)
823        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
824        self.assertRaises(
825            LinkNotFoundError,
826            self.browser.getLink, 'Get Matriculation Number')
827        # Setting matric number is logged.
828        logfile = os.path.join(
829            self.app['datacenter'].storage, 'logs', 'students.log')
830        logcontent = open(logfile).read()
831        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
832                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
833        # Matric Number Slip can be downloaded
834        self.browser.getLink("Download matriculation number slip").click()
835        self.assertEqual(self.browser.headers['Status'], '200 Ok')
836        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
837        path = os.path.join(samples_dir(), 'matric_number_slip.pdf')
838        open(path, 'wb').write(self.browser.contents)
839        print "Sample PDF matric_number_slip.pdf written to %s" % path
840        return
841
842    def test_personal_data_slip(self):
843        # Login as student
844        self.browser.open(self.login_path)
845        IWorkflowState(self.student).setState('school fee paid')
846        self.browser.open(self.login_path)
847        self.browser.getControl(name="form.login").value = self.student_id
848        self.browser.getControl(name="form.password").value = 'spwd'
849        self.browser.getControl("Login").click()
850        self.browser.getLink("Personal Data").click()
851        self.assertRaises(
852            LinkNotFoundError,
853            self.browser.getLink, 'Download personal data slip')
854        self.student.father_name = u'Rudolf'
855        self.browser.open(self.personal_path)
856        self.browser.getLink("Download personal data slip").click()
857        self.assertEqual(self.browser.headers['Status'], '200 Ok')
858        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
859        path = os.path.join(samples_dir(), 'personal_data_slip.pdf')
860        open(path, 'wb').write(self.browser.contents)
861        print "Sample PDF personal_data_slip.pdf written to %s" % path
862        return
863
864    def test_student_course_registration(self):
865        IWorkflowState(self.student).setState('school fee paid')
866        self.browser.open(self.login_path)
867        self.browser.getControl(name="form.login").value = self.student_id
868        self.browser.getControl(name="form.password").value = 'spwd'
869        self.browser.getControl("Login").click()
870        # Now students can add the current study level
871        self.browser.getLink("Study Course").click()
872        self.browser.getLink("Add course list").click()
873        self.assertMatches('...Add current level 100 (Year 1)...',
874                           self.browser.contents)
875        self.browser.getControl("Create course list now").click()
876        # Students can't open the customized pdf course registration slip
877        self.browser.open(
878            self.student_path + '/studycourse/100/course_registration_slip.pdf')
879        self.assertTrue('Forbidden' in self.browser.contents)
880        # They can open slips from the previous session ...
881        self.student['studycourse'].current_level = 200
882        self.browser.open(self.student_path + '/studycourse/100')
883        self.browser.getLink("Download course registration slip").click()
884        self.assertEqual(self.browser.headers['Status'], '200 Ok')
885        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
886        # or if they have registered their course list
887        self.student['studycourse'].current_level = 200
888        IWorkflowState(self.student).setState('courses registered')
889        self.browser.open(self.student_path + '/studycourse/100')
890        self.browser.getLink("Download course registration slip").click()
891        self.assertEqual(self.browser.headers['Status'], '200 Ok')
892        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
893        path = os.path.join(samples_dir(), 'ft_course_registration_slip.pdf')
894        open(path, 'wb').write(self.browser.contents)
895        print "Sample PDF ft_course_registration_slip.pdf written to %s" % path
896
897        self.certificate.study_mode = 'ug_pt'
898        self.browser.open(self.student_path + '/studycourse/100')
899        self.browser.getLink("Download course registration slip").click()
900        self.assertEqual(self.browser.headers['Status'], '200 Ok')
901        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
902        path = os.path.join(samples_dir(), 'pt_course_registration_slip.pdf')
903        open(path, 'wb').write(self.browser.contents)
904        print "Sample PDF pt_course_registration_slip.pdf written to %s" % path
905
906        self.certificate.study_mode = 'special_pg_ft'
907        self.student.matric_number = u'AAU/SPS/FLW/LAW/15/PHD/09504'
908        self.browser.open(self.student_path + '/studycourse/100')
909        self.browser.getLink("Download course registration slip").click()
910        self.assertEqual(self.browser.headers['Status'], '200 Ok')
911        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
912        path = os.path.join(samples_dir(), 'pg_course_registration_slip.pdf')
913        open(path, 'wb').write(self.browser.contents)
914        print "Sample PDF pg_course_registration_slip.pdf written to %s" % path
915
916        # Students cant' view scores, cas and grades.
917        self.browser.open(self.student_path + '/studycourse/100')
918        self.assertFalse('Score' in self.browser.contents)
919        self.assertFalse('CA' in self.browser.contents)
920        self.assertFalse('Grade' in self.browser.contents)
921        self.browser.getLink("COURSE1").click()
922        self.browser.open(self.student_path + '/studycourse/100')
923        self.assertFalse('Score' in self.browser.contents)
924        self.assertFalse('CA' in self.browser.contents)
925        self.assertFalse('Grade' in self.browser.contents)
926
927    def test_student_2nd_semester_course_registration(self):
928        IWorkflowState(self.student).setState('school fee paid')
929        self.student['studycourse'].entry_session = 2015
930        self.course.semester = 2
931        self.browser.open(self.login_path)
932        self.browser.getControl(name="form.login").value = self.student_id
933        self.browser.getControl(name="form.password").value = 'spwd'
934        self.browser.getControl("Login").click()
935        self.browser.getLink("Study Course").click()
936        self.browser.getLink("Add course list").click()
937        self.browser.getControl("Create course list now").click()
938        self.assertFalse('COURSE1' in self.browser.contents)
939        # 2nd semester tickets can't be added manually
940        self.browser.getLink("Edit course list").click()
941        self.browser.getLink("here").click()
942        self.browser.getControl(name="form.course").value = ['COURSE1']
943        self.browser.getControl("Add course ticket").click()
944        self.assertTrue(
945            'COURSE1 is a 2nd semester course which can only '
946            'be added if school fees have been fully paid.'
947            in self.browser.contents)
948        # 2nd instalment has to be paid first
949        self.certificate.school_fee_3 = 678.0
950        self.browser.open(self.payments_path + '/addop')
951        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
952        self.browser.getControl("Create ticket").click()
953        self.student['payments'].values()[0].approve()
954        self.browser.open(self.studycourse_path + '/100/ctadd')
955        self.browser.getControl(name="form.course").value = ['COURSE1']
956        self.browser.getControl("Add course ticket").click()
957        self.assertTrue('Successfully added COURSE1' in self.browser.contents)
958        return
959
960    def test_student_GST_registration(self):
961        configuration_1 = createObject('waeup.SessionConfiguration')
962        configuration_1.academic_session = 2016
963        configuration_1.gst_registration_1_fee = 3333.0
964        configuration_1.gst_text_book_1_fee = 4444.0
965        configuration_1.gst_text_book_0_fee = 2222.0
966        self.app['configuration'].addSessionConfiguration(configuration_1)
967        course = createObject('waeup.Course')
968        course.code = 'GST101'
969        course.semester = 1
970        course.credits = 10
971        course.passmark = 40
972        self.app['faculties']['fac1']['dep1'].courses.addCourse(
973            course)
974        self.app['faculties']['fac1']['dep1'].certificates[
975            'CERT1'].addCertCourse(course, level=100)
976        IWorkflowState(self.student).setState('school fee paid')
977        self.student['studycourse'].entry_session = 2016
978        self.student['studycourse'].current_session = 2016
979        self.course.semester = 2
980        self.browser.open(self.login_path)
981        self.browser.getControl(name="form.login").value = self.student_id
982        self.browser.getControl(name="form.password").value = 'spwd'
983        self.browser.getControl("Login").click()
984        self.browser.getLink("Study Course").click()
985        self.browser.getLink("Add course list").click()
986        self.browser.getControl("Create course list now").click()
987        self.assertFalse('GST101' in self.browser.contents)
988        # GST101 tickets can't be added manually
989        self.browser.getLink("Edit course list").click()
990        self.browser.getLink("here").click()
991        self.browser.getControl(name="form.course").value = ['GST101']
992        self.browser.getControl("Add course ticket").click()
993        self.assertTrue(
994            'GST101 can only be added if both registration fee and text'
995            in self.browser.contents)
996        # GST fees have to be paid first
997        self.browser.open(self.payments_path + '/addop')
998        self.browser.getControl(name="form.p_category").value = ['gst_registration_1']
999        self.browser.getControl("Create ticket").click()
1000        self.student['payments'].values()[0].approve()
1001        self.browser.open(self.studycourse_path + '/100/ctadd')
1002        self.browser.getControl(name="form.course").value = ['GST101']
1003        self.browser.getControl("Add course ticket").click()
1004        self.assertTrue(
1005            'GST101 can only be added if both registration fee and text'
1006            in self.browser.contents)
1007        self.browser.open(self.payments_path + '/addop')
1008        self.browser.getControl(name="form.p_category").value = ['gst_text_book_0']
1009        self.browser.getControl("Create ticket").click()
1010        self.student['payments'].values()[1].approve()
1011        self.browser.open(self.studycourse_path + '/100/ctadd')
1012        self.browser.getControl(name="form.course").value = ['GST101']
1013        self.browser.getControl("Add course ticket").click()
1014        self.assertTrue('Successfully added GST101' in self.browser.contents)
1015        return
1016
1017    def test_course_registration_forbidden(self):
1018        IWorkflowState(self.student).setState('school fee paid')
1019        self.student['studycourse'].entry_session = 2016
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        #self.assertTrue('Please pay faculty and departmental dues first'
1031        #    in self.browser.contents)
1032        #configuration_1 = createObject('waeup.SessionConfiguration')
1033        #configuration_1.academic_session = 2016
1034        #configuration_1.fac_dep_fee = 9999.0
1035        #self.app['configuration'].addSessionConfiguration(configuration_1)
1036        #self.browser.open(self.payments_path + '/addop')
1037        #self.browser.getControl(name="form.p_category").value = ['fac_dep']
1038        #self.browser.getControl("Create ticket").click()
1039        #self.student['payments'].values()[0].approveStudentPayment()
1040        #self.browser.open(self.studycourse_path + '/100/edit')
1041        #self.browser.getControl("Register course list").click()
1042
1043        ######################################################
1044        # Temporarily disabled ug_ft course registration
1045        #self.assertTrue('Course registration has been disabled'
1046        #    in self.browser.contents)
1047        #return
1048        ######################################################
1049
1050        self.assertTrue('Course list has been registered'
1051            in self.browser.contents)
1052        return
1053
1054    def test_course_registration_forbidden_2(self):
1055        IWorkflowState(self.student).setState('school fee paid')
1056        self.student['studycourse'].entry_session = 2004
1057        self.student['studycourse'].current_session = 2016
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.browser.getLink("Edit course list").click()
1066        self.browser.getControl("Register course list").click()
1067
1068        ######################################################
1069        # Temporarily disabled ug_ft course registration
1070        #self.assertTrue('Course registration has been disabled'
1071        #    in self.browser.contents)
1072        #return
1073        ######################################################
1074
1075        self.assertTrue('Please pay restitution fee first'
1076            in self.browser.contents)
1077        configuration = createObject('waeup.SessionConfiguration')
1078        configuration.academic_session = 2016
1079        self.app['configuration'].addSessionConfiguration(configuration)
1080        self.app['configuration']['2016'].restitution_fee = 9999.0
1081        self.browser.open(self.payments_path + '/addop')
1082        self.browser.getControl(name="form.p_category").value = ['restitution']
1083        self.browser.getControl("Create ticket").click()
1084        self.student['payments'].values()[0].approveStudentPayment()
1085        self.browser.open(self.studycourse_path + '/100/edit')
1086        self.browser.getControl("Register course list").click()
1087        self.assertTrue('Course list has been registered'
1088            in self.browser.contents)
1089        return
1090
1091    def test_student_access_course_results(self):
1092        IWorkflowState(self.student).setState('school fee paid')
1093        self.student['studycourse'].entry_session = 2004
1094        self.student['studycourse'].current_session = 2004
1095        self.browser.open(self.login_path)
1096        self.browser.getControl(name="form.login").value = self.student_id
1097        self.browser.getControl(name="form.password").value = 'spwd'
1098        self.browser.getControl("Login").click()
1099        self.browser.getLink("Study Course").click()
1100        self.browser.getLink("Add course list").click()
1101        self.browser.getControl("Create course list now").click()
1102        self.assertFalse('Score' in self.browser.contents)
1103        IWorkflowState(self.student).setState('returning')
1104        self.browser.open(self.studycourse_path + '/100')
1105        self.assertFalse('Score' in self.browser.contents)
1106        self.app['configuration']['2004'].show_results = ['ug_ft']
1107        self.browser.open(self.studycourse_path + '/100')
1108        self.assertTrue('Score' in self.browser.contents)
1109        return
1110
1111    def test_repair_course_list(self):
1112        IWorkflowState(self.student).setState('school fee paid')
1113        self.student['studycourse'].entry_session = 2016
1114        self.student['studycourse'].current_session = 2016
1115        self.browser.open(self.login_path)
1116        self.browser.getControl(name="form.login").value = self.student_id
1117        self.browser.getControl(name="form.password").value = 'spwd'
1118        self.browser.getControl("Login").click()
1119        self.browser.getLink("Study Course").click()
1120        self.browser.getLink("Add course list").click()
1121        self.browser.getControl("Create course list now").click()
1122        self.assertTrue('Edit course list' in self.browser.contents)
1123        self.assertFalse('Repair course list' in self.browser.contents)
1124        self.student['studycourse'].current_level = 200
1125        self.browser.open(self.studycourse_path + '/100')
1126        self.assertFalse('Edit course list' in self.browser.contents)
1127        self.assertFalse('Repair course list' in self.browser.contents)
1128        configuration = createObject('waeup.SessionConfiguration')
1129        configuration.academic_session = 2016
1130        self.app['configuration'].addSessionConfiguration(configuration)
1131        self.app['configuration']['2016'].studylevel_repair_enabled = True
1132        self.browser.open(self.studycourse_path + '/100')
1133        self.assertFalse('Edit course list' in self.browser.contents)
1134        self.assertTrue('Repair course list' in self.browser.contents)
1135        self.browser.getLink("Repair").click()
1136        self.assertEqual(self.browser.url, self.studycourse_path + '/100/repair')
1137        self.assertTrue('Repair course list of 100' in self.browser.contents)
1138        return
1139
1140    def test_student_clearance(self):
1141        # Student cant login if their password is not set
1142        IWorkflowInfo(self.student).fireTransition('admit')
1143        self.browser.open(self.login_path)
1144        self.browser.getControl(name="form.login").value = self.student_id
1145        self.browser.getControl(name="form.password").value = 'spwd'
1146        self.browser.getControl("Login").click()
1147        self.assertMatches(
1148            '...You logged in...', self.browser.contents)
1149        # Admitted student can upload a passport picture
1150        self.browser.open(self.student_path + '/change_portrait')
1151        ctrl = self.browser.getControl(name='passportuploadedit')
1152        file_obj = open(SAMPLE_IMAGE, 'rb')
1153        file_ctrl = ctrl.mech_control
1154        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
1155        self.browser.getControl(
1156            name='upload_passportuploadedit').click()
1157        self.assertTrue(
1158            'src="http://localhost/app/students/E1000000/passport.jpg"'
1159            in self.browser.contents)
1160        # Student is redirected to the personal data form because
1161        # personal data form is not properly filled.
1162        self.browser.open(self.student_path + '/start_clearance')
1163        self.assertMatches('...Personal data form is not properly filled...',
1164                           self.browser.contents)
1165        self.assertEqual(self.browser.url, self.student_path + '/edit_personal')
1166        self.student.father_name = u'Rudolf'
1167        self.browser.open(self.student_path + '/start_clearance')
1168        self.assertMatches(
1169            '...<h1 class="kofa-content-label">Start clearance</h1>...',
1170            self.browser.contents)
1171
1172    def test_student_accommodation(self):
1173        del self.student['accommodation']['2004']
1174        self.student['studycourse'].certificate.study_mode = 'dp_ft'
1175        # All beds can be assigned
1176        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
1177        bed1.bed_type = u'regular_male_all'
1178        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
1179        bed2.bed_type = u'regular_female_all'
1180        notify(grok.ObjectModifiedEvent(bed1))
1181        notify(grok.ObjectModifiedEvent(bed2))
1182        # Login
1183        self.browser.open(self.login_path)
1184        self.browser.getControl(name="form.login").value = self.student_id
1185        self.browser.getControl(name="form.password").value = 'spwd'
1186        self.browser.getControl("Login").click()
1187        # Students can book accommodation without AC ...
1188        self.browser.open(self.acco_path)
1189        IWorkflowInfo(self.student).fireTransition('admit')
1190        self.browser.getControl("Book accommodation").click()
1191        self.assertTrue(
1192            'You are not eligible to book accommodation.'
1193            in self.browser.contents)
1194        self.student['studycourse'].certificate.study_mode = 'ug_ft'
1195        self.app['hostels'].accommodation_states = [PAID]
1196        self.browser.getControl("Book accommodation").click()
1197        self.assertTrue(
1198            'You are in the wrong registration state.'
1199            in self.browser.contents)
1200        IWorkflowState(self.student).setState(PAID)
1201        self.browser.getControl("Book accommodation").click()
1202        self.assertFalse('Activation Code:' in self.browser.contents)
1203        self.browser.getControl("Create bed ticket").click()
1204        # Bed is randomly selected but, since there is only
1205        # one bed for this student, we know that
1206        self.assertEqual(self.student['accommodation']['2004'].bed_coordinates,
1207            'Hall 1, Block A, Room 101, Bed A (regular_male_all)')
1208        # Only the hall name is displayed
1209        self.assertEqual(self.student[
1210            'accommodation']['2004'].display_coordinates,
1211            'Hall 1')
1212        self.assertFalse('Hall 1, Block A, Room 101, Bed A'
1213            in self.browser.contents)
1214        self.assertTrue('<td>Hall 1</td>'
1215            in self.browser.contents)
1216        return
1217
1218    def test_handle_courses_by_lecturer(self):
1219        self.app['users'].addUser('mrslecturer', 'mrslecturerSecret1')
1220        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
1221        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
1222        # Add course ticket
1223        studylevel = createObject(u'waeup.StudentStudyLevel')
1224        studylevel.level = 100
1225        studylevel.level_session = 2004
1226        self.student['studycourse'].addStudentStudyLevel(
1227            self.certificate, studylevel)
1228        # Assign local Lecturer role for a certificate.
1229        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
1230        prmlocal = IPrincipalRoleManager(course)
1231        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
1232        notify(LocalRoleSetEvent(
1233            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
1234        # Login as lecturer.
1235        self.browser.open(self.login_path)
1236        self.browser.getControl(name="form.login").value = 'mrslecturer'
1237        self.browser.getControl(name="form.password").value = 'mrslecturerSecret1'
1238        self.browser.getControl("Login").click()
1239        self.browser.getLink("My Courses").click()
1240        self.browser.getLink("COURSE1").click()
1241        # Course results can be batch edited via the edit_courses view.
1242        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
1243        self.app['configuration'].current_academic_session = 2004
1244        self.app['configuration']['2004'].score_editing_enabled = ['ug_ft']
1245        IWorkflowState(self.student).setState('courses validated')
1246        self.browser.open(
1247            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
1248        self.assertTrue(
1249            'input type="text" name="scores:list"'
1250            in self.browser.contents)
1251        self.browser.getControl(name="scores:list", index=0).value = '55'
1252        self.browser.getControl(name="cas:list", index=0).value = '22'
1253        self.browser.getControl("Update scores from").click()
1254        # New score and ca has been set.
1255        self.assertEqual(
1256            self.student['studycourse']['100']['COURSE1'].score, 55)
1257        self.assertEqual(
1258            self.student['studycourse']['100']['COURSE1'].ca, 22)
1259        # Score editing has been logged.
1260        logfile = os.path.join(
1261            self.app['datacenter'].storage, 'logs', 'students.log')
1262        logcontent = open(logfile).read()
1263        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
1264                        'E1000000 100/COURSE1 score updated (55)' in logcontent)
1265        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
1266                        'E1000000 100/COURSE1 ca updated (22)' in logcontent)
1267        # Non-integer scores won't be accepted.
1268        self.browser.open(
1269            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
1270        self.assertTrue('value="55" />' in self.browser.contents)
1271        self.browser.getControl(name="scores:list", index=0).value = 'abc'
1272        self.browser.getControl("Update scores").click()
1273        self.assertTrue('Error: Score(s), CA(s) and Imported TS(s) of TESTER, Anna have not be updated.'
1274            in self.browser.contents)
1275        # Scores can be removed.
1276        self.browser.open(
1277            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
1278        self.browser.getControl(name="scores:list", index=0).value = ''
1279        self.browser.getControl("Update scores").click()
1280        self.assertEqual(
1281            self.student['studycourse']['100']['COURSE1'].score, None)
1282        logcontent = open(logfile).read()
1283        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
1284                        'E1000000 100/COURSE1 score updated (None)' in logcontent)
1285
1286
1287    def disabled_test_student_view_transcript(self):
1288        # Student cant login if their password is not set
1289        IWorkflowInfo(self.student).fireTransition('admit')
1290        self.browser.open(self.login_path)
1291        self.browser.getControl(name="form.login").value = self.student_id
1292        self.browser.getControl(name="form.password").value = 'spwd'
1293        self.browser.getControl("Login").click()
1294        self.assertMatches(
1295            '...You logged in...', self.browser.contents)
1296        # Students can view the transcript
1297        self.browser.open(self.studycourse_path)
1298        self.browser.getLink("Transcript").click()
1299        self.browser.getLink("Academic Transcript").click()
1300        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1301        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1302
1303    def test_alumni_request_pw(self):
1304        # Add an applicants container
1305        applicantscontainer = ApplicantsContainer()
1306        applicantscontainer.code = u'trans2017'
1307        applicantscontainer.prefix = 'trans'
1308        applicantscontainer.year = 2017
1309        applicantscontainer.title = u'This is the trans2017 container'
1310        applicantscontainer.application_category = 'no'
1311        applicantscontainer.mode = 'create'
1312        applicantscontainer.strict_deadline = True
1313        delta = timedelta(days=10)
1314        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
1315        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
1316        self.app['applicants']['trans2017'] = applicantscontainer
1317        self.applicantscontainer = self.app['applicants']['trans2017']
1318        # Student with wrong number can't be found.
1319        # Applicant is redirected to application section.
1320        self.browser.open('http://localhost/app/alumni_requestpw')
1321        self.browser.getControl(name="form.lastname").value = 'Tester'
1322        self.browser.getControl(name="form.number").value = 'anynumber'
1323        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1324        self.browser.getControl("Send login credentials").click()
1325        self.assertTrue('No student record found.'
1326            in self.browser.contents)
1327        self.assertEqual(self.browser.url,
1328            'http://localhost/app/applicants/trans2017/register')
1329
1330    def test_student_course_registration_outstanding(self):
1331        self.course = createObject('waeup.Course')
1332        self.course.code = 'COURSE2'
1333        self.course.semester = 1
1334        self.course.credits = 39
1335        self.course.passmark = 40
1336        self.app['faculties']['fac1']['dep1'].courses.addCourse(
1337            self.course)
1338        IWorkflowState(self.student).setState('school fee paid')
1339        self.browser.open(self.login_path)
1340        self.browser.getControl(name="form.login").value = self.student_id
1341        self.browser.getControl(name="form.password").value = 'spwd'
1342        self.browser.getControl("Login").click()
1343        self.browser.open(self.student_path + '/studycourse/add')
1344        self.browser.getControl("Create course list now").click()
1345        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 1)
1346        self.student['studycourse'].current_level = 200
1347        self.browser.getLink("Study Course").click()
1348        self.browser.getLink("Add course list").click()
1349        self.assertMatches('...Add current level 200 (Year 2)...',
1350                           self.browser.contents)
1351        self.browser.getControl("Create course list now").click()
1352        self.browser.getLink("200").click()
1353        self.browser.getLink("Edit course list").click()
1354        self.browser.getLink("here").click()
1355        self.browser.getControl(name="form.course").value = ['COURSE2']
1356        self.browser.getControl("Add course ticket").click()
1357        # Carryover COURSE1 in level 200 already has 10 credits
1358        self.assertMatches(
1359            '...Maximum credits exceeded...', self.browser.contents)
1360        # If COURSE1 is outstanding, its credits won't be considered
1361        self.student['studycourse']['200']['COURSE1'].outstanding = True
1362        self.browser.getControl("Add course ticket").click()
1363        # Corresponding certificate course is missing
1364        self.assertTrue(
1365            'COURSE2 is not part of the CERT1 curriculum.'
1366            in self.browser.contents)
1367        self.app['faculties']['fac1']['dep1'].certificates[
1368            'CERT1'].addCertCourse(self.course, level=100)
1369        self.browser.getControl("Add course ticket").click()
1370        self.assertTrue(
1371            'Successfully added COURSE2' in self.browser.contents)
1372        return
1373
1374    def test_examination_schedule_slip(self):
1375        self.student.flash_notice = u'My Examination Date'
1376        self.browser.open(self.login_path)
1377        self.browser.getControl(name="form.login").value = self.student_id
1378        self.browser.getControl(name="form.password").value = 'spwd'
1379        self.browser.getControl("Login").click()
1380        self.browser.getLink("Download examination schedule slip").click()
1381        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1382        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1383        path = os.path.join(samples_dir(), 'examination_schedule_slip.pdf')
1384        open(path, 'wb').write(self.browser.contents)
1385        print "Sample PDF examination_schedule_slip.pdf written to %s" % path
1386        # If flash_notive does not contain exam' the button does not show up.
1387        self.student.flash_notice = u'anything'
1388        self.browser.open(self.student_path)
1389        self.assertFalse('examination schedule slip' in self.browser.contents)
Note: See TracBrowser for help on using the repository browser.