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

Last change on this file since 16673 was 16355, checked in by Henrik Bettermann, 4 years ago

Repair test.

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