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

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

Add test

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