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

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

Implement course list repair page.

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