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

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

Process title if too long.

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