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

Last change on this file since 15338 was 15338, checked in by Henrik Bettermann, 6 years ago

Deactivate eTranzact payments.

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