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

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

Show different warming message if late course registration fee is not set.

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