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

Last change on this file since 14701 was 14701, checked in by Henrik Bettermann, 7 years ago

Add fields to CustomDataForLecturerExporter?.

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