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

Last change on this file since 14292 was 14288, checked in by Henrik Bettermann, 8 years ago

Lecturers can edit current session and previous session courses whenever they like. All restrictions are removed.

  • Property svn:keywords set to Id
File size: 57.2 KB
Line 
1## $Id: test_browser.py 14288 2016-11-18 07:19:25Z 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.aaue.testing import FunctionalLayer
41
42SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
43
44
45UPLOAD_CSV_TEMPLATE = (
46    'matric_number,student_id,display_fullname,level,code,level_session,'
47    'score,ca\r\n'
48    '234,E1000000,Anna Tester,100,COURSE1,2004,%s,%s\r\n')
49
50class OfficerUITests(StudentsFullSetup):
51    # Tests for Student class views and pages
52
53    layer = FunctionalLayer
54
55    def login_as_lecturer(self):
56        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
57        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
58        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
59        # Add course ticket
60        studylevel = createObject(u'waeup.StudentStudyLevel')
61        studylevel.level = 100
62        studylevel.level_session = 2004
63        self.student['studycourse'].addStudentStudyLevel(
64            self.certificate, studylevel)
65        # Assign local Lecturer role for a certificate.
66        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
67        prmlocal = IPrincipalRoleManager(course)
68        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
69        notify(LocalRoleSetEvent(
70            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
71        # Login as lecturer.
72        self.browser.open(self.login_path)
73        self.browser.getControl(name="form.login").value = 'mrslecturer'
74        self.browser.getControl(
75            name="form.password").value = 'mrslecturersecret'
76        self.browser.getControl("Login").click()
77        # Store reused urls/paths
78        self.course_url = (
79            'http://localhost/app/faculties/fac1/dep1/courses/COURSE1')
80        self.edit_scores_url = '%s/edit_scores' % self.course_url
81        self.edit_prev_scores_url = '%s/edit_prev_scores' % self.course_url
82        # Set standard parameters
83        self.app['configuration'].current_academic_session = 2004
84        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
85        IWorkflowState(self.student).setState(VALIDATED)
86
87
88    def test_gpa_calculation(self):
89        studylevel = createObject(u'waeup.StudentStudyLevel')
90        studylevel.level = 100
91        studylevel.level_session = 2005
92        self.student['studycourse'].entry_mode = 'ug_ft'
93        self.student['studycourse'].addStudentStudyLevel(
94            self.certificate, studylevel)
95        # First course has been added automatically.
96        # Set score.
97        studylevel['COURSE1'].score = 35
98        studylevel['COURSE1'].ca = 20
99        # GPA is 3.0.
100        self.assertEqual(studylevel.gpa_params[0], 3.0)
101        courseticket = createObject('waeup.CourseTicket')
102        courseticket.code = 'ANYCODE'
103        courseticket.title = u'Any TITLE'
104        courseticket.credits = 13
105        courseticket.score = 44
106        courseticket.ca = 22
107        courseticket.semester = 1
108        courseticket.dcode = u'ANYDCODE'
109        courseticket.fcode = u'ANYFCODE'
110        studylevel['COURSE2'] = courseticket
111        # total credits
112        self.assertEqual(self.student['studycourse']['100'].gpa_params[1], 23)
113        # weigheted credits = 3 * 10 + 4 * 13
114        self.assertEqual(self.student['studycourse']['100'].gpa_params[2], 82.0)
115        # sgpa = 82 / 23
116        self.assertEqual(
117            self.student['studycourse']['100'].gpa_params[0], 3.565)
118        # imported gpa values override calculated values
119        studylevel.imported_gpa = 4.3
120        studylevel.imported_cgpa = 5.4
121        self.assertEqual(self.student['studycourse']['100'].gpa_params[0], 4.3)
122        self.assertEqual(
123            self.student['studycourse']['100'].cumulative_params[0], 5.4)
124        self.assertEqual(self.student['studycourse']['100'].gpa, 4.3)
125        self.student['studycourse'].imported_cgpa = 6.6
126        self.assertEqual(
127            self.student['studycourse'].getTranscriptData()[1], 6.6)
128        return
129
130    def test_grade_weight(self):
131        studylevel = createObject(u'waeup.StudentStudyLevel')
132        studylevel.level = 100
133        studylevel.level_session = 2005
134        self.student['studycourse'].entry_mode = 'ug_ft'
135        self.student['studycourse'].addStudentStudyLevel(
136            self.certificate, studylevel)
137        studylevel['COURSE1'].score = 42
138        studylevel['COURSE1'].ca = 0
139        courseticket = createObject('waeup.CourseTicket')
140        self.assertEqual(studylevel['COURSE1'].weight, 1)
141        self.assertEqual(studylevel['COURSE1'].grade, 'E')
142        self.student['studycourse'].entry_session = 2015
143        self.assertEqual(studylevel['COURSE1'].weight, 0)
144        self.assertEqual(studylevel['COURSE1'].grade, 'F')
145        studylevel['COURSE1'].score = 45
146        self.assertEqual(studylevel['COURSE1'].weight, 2)
147        self.assertEqual(studylevel['COURSE1'].grade, 'D')
148        return
149
150    def test_manage_payments(self):
151        # Add missing configuration data
152        self.app['configuration']['2004'].gown_fee = 150.0
153        self.app['configuration']['2004'].transfer_fee = 90.0
154        self.app['configuration']['2004'].booking_fee = 150.0
155        self.app['configuration']['2004'].maint_fee = 180.0
156        self.app['configuration']['2004'].late_fee = 80.0
157
158        # Managers can add online payment tickets
159        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
160        self.browser.open(self.payments_path)
161        self.browser.getLink("Add current session payment ticket").click()
162        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
163        self.browser.getControl("Create ticket").click()
164        self.assertMatches('...Wrong state...',
165                           self.browser.contents)
166        IWorkflowState(self.student).setState('cleared')
167        self.browser.open(self.payments_path + '/addop')
168        self.app['configuration']['2004'].clearance_fee = 666.0
169        self.browser.getControl(name="form.p_category").value = ['clearance_incl']
170        self.browser.getControl("Create ticket").click()
171        ctrl = self.browser.getControl(name='val_id')
172        cpt_value = ctrl.options[0]
173        # School fee payment ticket can be added ...
174        self.student['studycourse'].certificate.school_fee_1 = 6666.0
175        self.student.nationality = u'NG'
176        self.browser.open(self.payments_path + '/addop')
177        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
178        self.browser.getControl("Create ticket").click()
179        self.assertMatches('...ticket created...',
180                           self.browser.contents)
181        # ... but not paid through the query_history page.
182        ctrl = self.browser.getControl(name='val_id')
183        sfpt_value = ctrl.options[1]
184        self.student['studycourse'].entry_session = 2013
185        self.browser.open(self.payments_path + '/' + sfpt_value)
186        self.browser.getLink("Query eTranzact History").click()
187        self.assertMatches('...alert-danger">Please pay acceptance fee first...',
188                           self.browser.contents)
189        # If clearance/acceptance fee is paid ...
190        self.student['payments'][cpt_value].approveStudentPayment()
191        self.browser.getLink("Query eTranzact History").click()
192        # ... query_history page is accessible.
193        self.assertMatches(
194            '...<h1 class="kofa-content-label">Requery eTranzact History</h1>...',
195            self.browser.contents)
196        # Managers can open school fee payment slip
197        self.browser.open(self.payments_path + '/' + sfpt_value)
198        self.browser.getLink("Download payment slip").click()
199        self.assertEqual(self.browser.headers['Status'], '200 Ok')
200        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
201        # If school fee ticket is paid, the student is automatically set to
202        # school fee paid...
203        ticket = self.student['payments'][sfpt_value].approveStudentPayment()
204        self.assertEqual(self.student.state, 'school fee paid')
205        # ... no further school fee ticket can be added.
206        self.browser.open(self.payments_path + '/addop')
207        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
208        self.browser.getControl("Create ticket").click()
209        self.assertMatches('...Wrong state...',
210                           self.browser.contents)
211        self.browser.open(self.payments_path + '/addop')
212        self.browser.getControl(name="form.p_category").value = ['late_registration']
213        self.browser.getControl("Create ticket").click()
214        self.assertMatches('...ticket created...',
215                           self.browser.contents)
216        return
217
218    def test_for_instalment_payments(self):
219
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.browser.open(self.edit_scores_url)
366        upload_ctrl = self.browser.getControl(name='uploadfile:file')
367        upload_file = StringIO(UPLOAD_CSV_TEMPLATE % ('65','22'))
368        upload_ctrl.add_file(upload_file, 'text/csv', 'myscores.csv')
369        self.browser.getControl("Update editable scores from").click()
370        # value changed
371        self.assertEqual(
372            self.student['studycourse']['100']['COURSE1'].score, 65)
373        self.assertEqual(
374            self.student['studycourse']['100']['COURSE1'].ca, 22)
375
376    def test_scores_previous_session(self):
377        # lecturers can download a CSV file to set values.
378        self.login_as_lecturer()
379        self.student['studycourse']['100']['COURSE1'].score = 55
380        self.browser.open(self.edit_prev_scores_url)
381        self.assertTrue('No student found' in self.browser.contents)
382        self.student['studycourse']['100'].level_session = 2003
383        notify(grok.ObjectModifiedEvent(self.student['studycourse']['100']['COURSE1']))
384        self.browser.open(self.edit_prev_scores_url)
385        self.browser.getLink("Download csv file").click()
386        self.assertEqual(self.browser.headers['Status'], '200 Ok')
387        self.assertEqual(self.browser.headers['Content-Type'],
388                         'text/csv; charset=UTF-8')
389        self.assertEqual(self.browser.contents, 'matric_number,student_id,'
390            'level,code,level_session,ca,score\r\n234,E1000000,'
391            '100,COURSE1,2003,,55\r\n')
392        self.browser.open(self.edit_prev_scores_url)
393        upload_ctrl = self.browser.getControl(name='uploadfile:file')
394        upload_file = StringIO(UPLOAD_CSV_TEMPLATE % ('65','22'))
395        upload_ctrl.add_file(upload_file, 'text/csv', 'myscores.csv')
396        self.browser.getControl("Update editable scores from").click()
397        # value changed
398        self.assertEqual(
399            self.student['studycourse']['100']['COURSE1'].score, 65)
400        self.assertEqual(
401            self.student['studycourse']['100']['COURSE1'].ca, 22)
402
403    def test_lecturers_can_download_course_tickets(self):
404        # A course ticket slip can be downloaded
405        self.login_as_lecturer()
406        pdf_url = '%s/coursetickets.pdf' % self.course_url
407        self.browser.open(pdf_url)
408        self.assertEqual(self.browser.headers['Status'], '200 Ok')
409        self.assertEqual(
410            self.browser.headers['Content-Type'], 'application/pdf')
411        path = os.path.join(samples_dir(), 'coursetickets.pdf')
412        open(path, 'wb').write(self.browser.contents)
413        print "Sample PDF coursetickets.pdf written to %s" % path
414
415    def test_transcripts(self):
416        studylevel = createObject(u'waeup.StudentStudyLevel')
417        studylevel.level = 100
418        studylevel.level_session = 2005
419        self.student['studycourse'].entry_mode = 'ug_ft'
420        self.student['studycourse'].addStudentStudyLevel(
421            self.certificate, studylevel)
422        studylevel2 = createObject(u'waeup.StudentStudyLevel')
423        studylevel2.level = 200
424        studylevel2.level_session = 2006
425        self.student['studycourse']['100']['COURSE1'].score = 33 # no carry-over!
426        self.student['studycourse']['100']['COURSE1'].ca = 22
427        self.student['studycourse'].addStudentStudyLevel(
428            self.certificate, studylevel2)
429        # Add second course (COURSE has been added automatically)
430        courseticket = createObject('waeup.CourseTicket')
431        courseticket.code = 'ANYCODE'
432        courseticket.title = u'Any TITLE'
433        courseticket.credits = 13
434        courseticket.score = 55
435        courseticket.ca = 11
436        courseticket.semester = 1
437        courseticket.dcode = u'ANYDCODE'
438        courseticket.fcode = u'ANYFCODE'
439        self.student['studycourse']['200']['COURSE2'] = courseticket
440        self.assertEqual(self.student['studycourse']['100'].gpa_params_rectified[0], 3.0)
441        self.assertEqual(self.student['studycourse']['200'].gpa_params_rectified[0], 4.0)
442        # Get transcript data
443        td = self.student['studycourse'].getTranscriptData()
444        self.assertEqual(td[0][0]['level_key'], '100')
445        self.assertEqual(td[0][0]['sgpa'], 3.0)
446        self.assertEqual(td[0][0]['level'].level, 100)
447        self.assertEqual(td[0][0]['level'].level_session, 2005)
448        self.assertEqual(td[0][0]['tickets_1'][0].code, 'COURSE1')
449        self.assertEqual(td[0][1]['level_key'], '200')
450        self.assertEqual(td[0][1]['sgpa'], 4.0)
451        self.assertEqual(td[0][1]['level'].level, 200)
452        self.assertEqual(td[0][1]['level'].level_session, 2006)
453        self.assertEqual(td[0][1]['tickets_1'][0].code, 'ANYCODE')
454        self.assertEqual(td[1], 3.57)
455        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
456        self.browser.open(self.student_path + '/studycourse/transcript')
457        self.assertEqual(self.browser.headers['Status'], '200 Ok')
458        self.assertTrue('Transcript' in self.browser.contents)
459        # Officers can open the pdf transcript
460        self.browser.open(self.student_path + '/studycourse/transcript.pdf')
461        self.assertEqual(self.browser.headers['Status'], '200 Ok')
462        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
463        path = os.path.join(samples_dir(), 'transcript.pdf')
464        open(path, 'wb').write(self.browser.contents)
465        print "Sample PDF transcript.pdf written to %s" % path
466
467    def test_payment_disabled(self):
468        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
469        self.browser.open(self.payments_path)
470        IWorkflowState(self.student).setState('cleared')
471        self.browser.getLink("Add current session payment ticket").click()
472        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
473        self.browser.getControl("Create ticket").click()
474        self.assertMatches('...ticket created...', self.browser.contents)
475        self.app['configuration']['2004'].payment_disabled = ['sf_all']
476        self.browser.getLink("Add current session payment ticket").click()
477        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
478        self.browser.getControl("Create ticket").click()
479        self.assertMatches('...This category of payments has been disabled...',
480                           self.browser.contents)
481
482        self.app['configuration']['2004'].payment_disabled = ['sf_pt']
483        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
484        self.browser.getControl("Create ticket").click()
485        self.assertMatches('...ticket created...', self.browser.contents)
486        self.certificate.study_mode = 'ug_pt'
487        self.browser.getLink("Add current session payment ticket").click()
488        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
489        self.browser.getControl("Create ticket").click()
490        self.assertMatches('...This category of payments has been disabled...',
491                           self.browser.contents)
492
493        self.app['configuration']['2004'].payment_disabled = ['sf_pg']
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.certificate.study_mode = 'special_pg_ft'
498        self.browser.getLink("Add current session payment ticket").click()
499        self.browser.getControl(name="form.p_category").value = ['schoolfee']
500        self.browser.getControl("Create ticket").click()
501        self.assertMatches('...This category of payments has been disabled...',
502                           self.browser.contents)
503        return
504
505class StudentUITests(StudentsFullSetup):
506    """Tests for customized student class views and pages
507    """
508
509    layer = FunctionalLayer
510
511    def setUp(self):
512        super(StudentUITests, self).setUp()
513
514        bedticket = BedTicket()
515        bedticket.booking_session = 2004
516        bedticket.bed_type = u'any bed type'
517        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
518        bedticket.bed_coordinates = u'My bed coordinates'
519        self.student['accommodation'].addBedTicket(bedticket)
520
521    def test_maintenance_fee_payment(self):
522        self.certificate.study_mode = 'ug_ft'
523        self.student['studycourse'].entry_session = 2013
524        self.student.nationality = u'NG'
525        IWorkflowState(self.student).setState('cleared')
526        self.browser.open(self.login_path)
527        self.browser.getControl(name="form.login").value = self.student_id
528        self.browser.getControl(name="form.password").value = 'spwd'
529        self.browser.getControl("Login").click()
530        self.browser.open(self.student_path + '/payments')
531        self.browser.getLink("Add current session payment ticket").click()
532        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
533        self.browser.getControl("Create ticket").click()
534        self.assertTrue('ticket created' in self.browser.contents)
535        value = self.student['payments'].keys()[0]
536        self.browser.getLink(value).click()
537        self.assertTrue('<span>My bed coordinates</span>' in self.browser.contents)
538        self.assertEqual(self.student['payments'][value].amount_auth, 876.0)
539        return
540
541    def test_student_schoolfee_payments(self):
542        configuration_1 = createObject('waeup.SessionConfiguration')
543        configuration_1.academic_session = 2016
544        self.app['configuration'].addSessionConfiguration(configuration_1)
545        self.certificate.study_mode = 'ug_ft'
546        self.student['studycourse'].entry_session = 2016
547        self.student['studycourse'].current_session = 2016
548        self.student['studycourse'].entry_mode = 'ug_ft'
549        self.student['studycourse'].certificate.school_fee_1 = 50250.0
550        self.app['configuration']['2016'].union_fee = 1250.0
551        self.app['configuration']['2016'].welfare_fee = 750.0
552        self.app['configuration']['2016'].id_card_fee = 350.0
553        self.student.nationality = u'NG'
554        # Login
555        IWorkflowState(self.student).setState('cleared')
556        self.browser.open(self.login_path)
557        self.browser.getControl(name="form.login").value = self.student_id
558        self.browser.getControl(name="form.password").value = 'spwd'
559        self.browser.getControl("Login").click()
560        # Test school fee payments
561        self.browser.open(self.student_path + '/payments')
562        self.browser.getLink("Add current session payment ticket").click()
563        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
564        self.browser.getControl("Create ticket").click()
565        self.assertTrue('ticket created' in self.browser.contents)
566        value = self.student['payments'].keys()[0]
567        self.browser.getLink(value).click()
568        self.assertTrue('Amount Authorized' in self.browser.contents)
569        # 50250 + 1000 + 500 + 100 = 51850
570        self.assertEqual(self.student['payments'][value].amount_auth, 51850.0)
571        self.browser.open(self.browser.url + '/payment_slip.pdf')
572        self.assertEqual(self.browser.headers['Status'], '200 Ok')
573        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
574        path = os.path.join(samples_dir(), 'payment_slip.pdf')
575        open(path, 'wb').write(self.browser.contents)
576        print "Sample PDF payment_slip.pdf written to %s" % path
577        # Another school fee payment cannot be added
578        self.student['payments'][value].approve()
579        self.browser.open(self.student_path + '/payments')
580        self.browser.getLink("Add current session payment ticket").click()
581        self.browser.getControl(name="form.p_category").value = ['schoolfee']
582        self.browser.getControl("Create ticket").click()
583        self.assertTrue(
584            'You must choose a payment which includes additional fees'
585            in self.browser.contents)
586        return
587
588    def test_late_registration(self):
589        # Login
590        delta = timedelta(days=10)
591        self.app['configuration'][
592            '2004'].coursereg_deadline = datetime.now(pytz.utc) - delta
593        IWorkflowState(self.student).setState('school fee paid')
594        # Current session is 2004. Here we test course registration for
595        # returning students.
596        self.student['studycourse'].entry_session = 2003
597        self.browser.open(self.login_path)
598        self.browser.getControl(name="form.login").value = self.student_id
599        self.browser.getControl(name="form.password").value = 'spwd'
600        self.browser.getControl("Login").click()
601        self.browser.open(self.payments_path)
602        self.browser.open(self.payments_path + '/addop')
603        self.browser.getControl(name="form.p_category").value = ['late_registration']
604        self.browser.getControl("Create ticket").click()
605        self.assertMatches('...ticket created...',
606                           self.browser.contents)
607        self.browser.getLink("Study Course").click()
608        self.browser.getLink("Add course list").click()
609        self.assertMatches('...Add current level 100 (Year 1)...',
610                           self.browser.contents)
611        self.browser.getControl("Create course list now").click()
612        self.student['studycourse']['100']['COURSE1'].score = 67
613        self.browser.getLink("100").click()
614        # Course results can't be seen
615        self.assertFalse('<td>67</td>' in self.browser.contents)
616        self.browser.getLink("Edit course list").click()
617        self.assertFalse('<td>67</td>' in self.browser.contents)
618        self.browser.getControl("Register course list").click()
619        self.assertTrue('Course registration has ended. Please pay' in self.browser.contents)
620        self.student['payments'].values()[0].approve()
621        self.browser.getControl("Register course list").click()
622        self.assertTrue('Course list has been registered' in self.browser.contents)
623        self.assertEqual(self.student.state, 'courses registered')
624        # Reset student and check if fresh students are always allowed to
625        # register courses.
626        self.student['studycourse'].entry_session = 2004
627        del self.student['payments'][self.student['payments'].keys()[0]]
628        IWorkflowState(self.student).setState('school fee paid')
629        self.browser.open(self.studycourse_path + '/100/edit')
630        self.browser.getControl("Register course list").click()
631        self.assertTrue('Course list has been registered' in self.browser.contents)
632        return
633
634
635    def deactivated_test_student_course_registration(self):
636        # Add more courses
637        self.course2 = createObject('waeup.Course')
638        self.course2.code = 'COURSE2'
639        self.course2.semester = 2
640        self.course2.credits = 10
641        self.course2.passmark = 40
642        self.app['faculties']['fac1']['dep1'].courses.addCourse(
643            self.course2)
644        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
645            self.course2, level=100)
646        self.course3 = createObject('waeup.Course')
647        self.course3.code = 'COURSE3'
648        self.course3.semester = 3
649        self.course3.credits = 10
650        self.course3.passmark = 40
651        self.app['faculties']['fac1']['dep1'].courses.addCourse(
652            self.course3)
653        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
654            self.course3, level=100)
655
656        # Login as student
657        self.browser.open(self.login_path)
658        IWorkflowState(self.student).setState('school fee paid')
659        self.browser.open(self.login_path)
660        self.browser.getControl(name="form.login").value = self.student_id
661        self.browser.getControl(name="form.password").value = 'spwd'
662        self.browser.getControl("Login").click()
663        # Students can add the current study level
664        self.browser.getLink("Study Course").click()
665        self.browser.getLink("Add course list").click()
666        self.assertMatches('...Add current level 100 (Year 1)...',
667                           self.browser.contents)
668        self.browser.getControl("Create course list now").click()
669        # Student has not paid second instalment, therefore a level
670        # with two course ticket was created (semester 1 and combined)
671        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
672        self.browser.getLink("100").click()
673        self.browser.getLink("Edit course list").click()
674        self.browser.getControl("Add course ticket").click()
675        # Student can't add second semester course
676        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
677        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
678        self.assertFalse('<option value="COURSE2">' in self.browser.contents)
679
680        # Let's remove level and see what happens after 2nd instalment payment
681        del(self.student['studycourse']['100'])
682        payment2 = createObject('waeup.StudentOnlinePayment')
683        payment2.p_category = u'schoolfee_2'
684        payment2.p_session = self.student.current_session
685        self.student['payments']['anykey'] = payment2
686        self.browser.open(self.studycourse_path)
687        self.browser.getLink("Add course list").click()
688        self.browser.getControl("Create course list now").click()
689        # Still only 2 tickets have been created since payment ticket
690        # was not paid
691        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
692        payment2.p_state = u'paid'
693        del(self.student['studycourse']['100'])
694        self.browser.open(self.studycourse_path)
695        self.browser.getLink("Add course list").click()
696        self.browser.getControl("Create course list now").click()
697        # Now 2nd semester course has been added
698        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
699        # Student can add second semester course
700        self.browser.getLink("100").click()
701        self.browser.getLink("Edit course list").click()
702        self.browser.getControl("Add course ticket").click()
703        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
704        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
705        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
706        return
707
708    def test_set_matric_number(self):
709        #payment = createObject('waeup.StudentOnlinePayment')
710        #payment.p_category = u'concessional'
711        #payment.p_id = u'anyid'
712        #payment.p_state = u'paid'
713        #self.student['payments']['anykey'] = payment
714        # Login as student
715        self.browser.open(self.login_path)
716        IWorkflowState(self.student).setState('school fee paid')
717        self.browser.open(self.login_path)
718        self.browser.getControl(name="form.login").value = self.student_id
719        self.browser.getControl(name="form.password").value = 'spwd'
720        self.browser.getControl("Login").click()
721        self.assertRaises(
722            LinkNotFoundError,
723            self.browser.getLink, 'Get Matriculation Number')
724        self.student.matric_number = None
725        site = grok.getSite()
726        site['configuration'].next_matric_integer = 1
727        self.student['studycourse'].certificate.study_mode = 'ug_pt'
728        self.browser.open(self.student_path)
729        self.assertRaises(
730            LinkNotFoundError,
731            self.browser.getLink, 'Download matriculation number slip')
732        self.browser.getLink("Get Matriculation Number").click()
733        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
734            in self.browser.contents)
735        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
736        self.assertRaises(
737            LinkNotFoundError,
738            self.browser.getLink, 'Get Matriculation Number')
739        # Setting matric number is logged.
740        logfile = os.path.join(
741            self.app['datacenter'].storage, 'logs', 'students.log')
742        logcontent = open(logfile).read()
743        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
744                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
745        # Matric Number Slip can be downloaded
746        self.browser.getLink("Download matriculation number slip").click()
747        self.assertEqual(self.browser.headers['Status'], '200 Ok')
748        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
749        path = os.path.join(samples_dir(), 'matric_number_slip.pdf')
750        open(path, 'wb').write(self.browser.contents)
751        print "Sample PDF matric_number_slip.pdf written to %s" % path
752        return
753
754    def test_personal_data_slip(self):
755        # Login as student
756        self.browser.open(self.login_path)
757        IWorkflowState(self.student).setState('school fee paid')
758        self.browser.open(self.login_path)
759        self.browser.getControl(name="form.login").value = self.student_id
760        self.browser.getControl(name="form.password").value = 'spwd'
761        self.browser.getControl("Login").click()
762        self.browser.getLink("Personal Data").click()
763        self.assertRaises(
764            LinkNotFoundError,
765            self.browser.getLink, 'Download personal data slip')
766        self.student.father_name = u'Rudolf'
767        self.browser.open(self.personal_path)
768        self.browser.getLink("Download personal data slip").click()
769        self.assertEqual(self.browser.headers['Status'], '200 Ok')
770        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
771        path = os.path.join(samples_dir(), 'personal_data_slip.pdf')
772        open(path, 'wb').write(self.browser.contents)
773        print "Sample PDF personal_data_slip.pdf written to %s" % path
774        return
775
776    def test_student_course_registration(self):
777        IWorkflowState(self.student).setState('school fee paid')
778        self.browser.open(self.login_path)
779        self.browser.getControl(name="form.login").value = self.student_id
780        self.browser.getControl(name="form.password").value = 'spwd'
781        self.browser.getControl("Login").click()
782        # Now students can add the current study level
783        self.browser.getLink("Study Course").click()
784        self.browser.getLink("Add course list").click()
785        self.assertMatches('...Add current level 100 (Year 1)...',
786                           self.browser.contents)
787        self.browser.getControl("Create course list now").click()
788        # Students can't open the customized pdf course registration slip
789        self.browser.open(
790            self.student_path + '/studycourse/100/course_registration_slip.pdf')
791        self.assertTrue('Forbidden' in self.browser.contents)
792        # They can open slips from the previous session ...
793        self.student['studycourse'].current_level = 200
794        self.browser.open(self.student_path + '/studycourse/100')
795        self.browser.getLink("Download course registration slip").click()
796        self.assertEqual(self.browser.headers['Status'], '200 Ok')
797        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
798        # or if they have registered their course list
799        self.student['studycourse'].current_level = 200
800        IWorkflowState(self.student).setState('courses registered')
801        self.browser.open(self.student_path + '/studycourse/100')
802        self.browser.getLink("Download course registration slip").click()
803        self.assertEqual(self.browser.headers['Status'], '200 Ok')
804        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
805        path = os.path.join(samples_dir(), 'ft_course_registration_slip.pdf')
806        open(path, 'wb').write(self.browser.contents)
807        print "Sample PDF ft_course_registration_slip.pdf written to %s" % path
808
809        self.certificate.study_mode = 'ug_pt'
810        self.browser.open(self.student_path + '/studycourse/100')
811        self.browser.getLink("Download course registration slip").click()
812        self.assertEqual(self.browser.headers['Status'], '200 Ok')
813        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
814        path = os.path.join(samples_dir(), 'pt_course_registration_slip.pdf')
815        open(path, 'wb').write(self.browser.contents)
816        print "Sample PDF pt_course_registration_slip.pdf written to %s" % path
817
818        self.certificate.study_mode = 'special_pg_ft'
819        self.student.matric_number = u'AAU/SPS/FLW/LAW/15/PHD/09504'
820        self.browser.open(self.student_path + '/studycourse/100')
821        self.browser.getLink("Download course registration 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(), 'pg_course_registration_slip.pdf')
825        open(path, 'wb').write(self.browser.contents)
826        print "Sample PDF pg_course_registration_slip.pdf written to %s" % path
827
828    def test_student_2nd_semester_course_registration(self):
829        IWorkflowState(self.student).setState('school fee paid')
830        self.student['studycourse'].entry_session = 2015
831        self.course.semester = 2
832        self.browser.open(self.login_path)
833        self.browser.getControl(name="form.login").value = self.student_id
834        self.browser.getControl(name="form.password").value = 'spwd'
835        self.browser.getControl("Login").click()
836        self.browser.getLink("Study Course").click()
837        self.browser.getLink("Add course list").click()
838        self.browser.getControl("Create course list now").click()
839        self.assertFalse('COURSE1' in self.browser.contents)
840        # 2nd semester tickets can't be added manually
841        self.browser.getLink("Edit course list").click()
842        self.browser.getLink("here").click()
843        self.browser.getControl(name="form.course").value = ['COURSE1']
844        self.browser.getControl("Add course ticket").click()
845        self.assertTrue(
846            'COURSE1 is a 2nd semester course which can only '
847            'be added if school fees have been fully paid.'
848            in self.browser.contents)
849        # 2nd instalment has to be paid first
850        self.certificate.school_fee_3 = 678.0
851        self.browser.open(self.payments_path + '/addop')
852        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
853        self.browser.getControl("Create ticket").click()
854        self.student['payments'].values()[0].approve()
855        self.browser.open(self.studycourse_path + '/100/ctadd')
856        self.browser.getControl(name="form.course").value = ['COURSE1']
857        self.browser.getControl("Add course ticket").click()
858        self.assertTrue('Successfully added COURSE1' in self.browser.contents)
859        return
860
861    def test_student_GST_registration(self):
862        configuration_1 = createObject('waeup.SessionConfiguration')
863        configuration_1.academic_session = 2016
864        configuration_1.gst_registration_1_fee = 3333.0
865        configuration_1.gst_text_book_1_fee = 4444.0
866        self.app['configuration'].addSessionConfiguration(configuration_1)
867        course = createObject('waeup.Course')
868        course.code = 'GST101'
869        course.semester = 1
870        course.credits = 10
871        course.passmark = 40
872        self.app['faculties']['fac1']['dep1'].courses.addCourse(
873            course)
874        self.app['faculties']['fac1']['dep1'].certificates[
875            'CERT1'].addCertCourse(course, level=100)
876        IWorkflowState(self.student).setState('school fee paid')
877        self.student['studycourse'].entry_session = 2016
878        self.student['studycourse'].current_session = 2016
879        self.course.semester = 2
880        self.browser.open(self.login_path)
881        self.browser.getControl(name="form.login").value = self.student_id
882        self.browser.getControl(name="form.password").value = 'spwd'
883        self.browser.getControl("Login").click()
884        self.browser.getLink("Study Course").click()
885        self.browser.getLink("Add course list").click()
886        self.browser.getControl("Create course list now").click()
887        self.assertFalse('GST101' in self.browser.contents)
888        # GST101 tickets can't be added manually
889        self.browser.getLink("Edit course list").click()
890        self.browser.getLink("here").click()
891        self.browser.getControl(name="form.course").value = ['GST101']
892        self.browser.getControl("Add course ticket").click()
893        self.assertTrue(
894            'GST101 can only be added if both registration fee and text'
895            in self.browser.contents)
896        # GST fees have to be paid first
897        self.browser.open(self.payments_path + '/addop')
898        self.browser.getControl(name="form.p_category").value = ['gst_registration_1']
899        self.browser.getControl("Create ticket").click()
900        self.student['payments'].values()[0].approve()
901        self.browser.open(self.studycourse_path + '/100/ctadd')
902        self.browser.getControl(name="form.course").value = ['GST101']
903        self.browser.getControl("Add course ticket").click()
904        self.assertTrue(
905            'GST101 can only be added if both registration fee and text'
906            in self.browser.contents)
907        self.browser.open(self.payments_path + '/addop')
908        self.browser.getControl(name="form.p_category").value = ['gst_text_book_1']
909        self.browser.getControl("Create ticket").click()
910        self.student['payments'].values()[1].approve()
911        self.browser.open(self.studycourse_path + '/100/ctadd')
912        self.browser.getControl(name="form.course").value = ['GST101']
913        self.browser.getControl("Add course ticket").click()
914        self.assertTrue('Successfully added GST101' in self.browser.contents)
915        return
916
917    def test_course_registration_forbidden(self):
918        IWorkflowState(self.student).setState('school fee paid')
919        self.student['studycourse'].entry_session = 2016
920        self.student['studycourse'].current_session = 2016
921        self.browser.open(self.login_path)
922        self.browser.getControl(name="form.login").value = self.student_id
923        self.browser.getControl(name="form.password").value = 'spwd'
924        self.browser.getControl("Login").click()
925        self.browser.getLink("Study Course").click()
926        self.browser.getLink("Add course list").click()
927        self.browser.getControl("Create course list now").click()
928        self.browser.getLink("Edit course list").click()
929        self.browser.getControl("Register course list").click()
930        self.assertTrue('Please pay faculty and departmental dues first'
931            in self.browser.contents)
932
933        configuration_1 = createObject('waeup.SessionConfiguration')
934        configuration_1.academic_session = 2016
935        configuration_1.fac_dep_fee = 9999.0
936        self.app['configuration'].addSessionConfiguration(configuration_1)
937
938        self.browser.open(self.payments_path + '/addop')
939        self.browser.getControl(name="form.p_category").value = ['fac_dep']
940        self.browser.getControl("Create ticket").click()
941        self.student['payments'].values()[0].approveStudentPayment()
942        self.browser.open(self.studycourse_path + '/100/edit')
943        self.browser.getControl("Register course list").click()
944        self.assertTrue('Course list has been registered'
945            in self.browser.contents)
946        return
947
948    def test_student_clearance(self):
949        # Student cant login if their password is not set
950        IWorkflowInfo(self.student).fireTransition('admit')
951        self.browser.open(self.login_path)
952        self.browser.getControl(name="form.login").value = self.student_id
953        self.browser.getControl(name="form.password").value = 'spwd'
954        self.browser.getControl("Login").click()
955        self.assertMatches(
956            '...You logged in...', self.browser.contents)
957        # Admitted student can upload a passport picture
958        self.browser.open(self.student_path + '/change_portrait')
959        ctrl = self.browser.getControl(name='passportuploadedit')
960        file_obj = open(SAMPLE_IMAGE, 'rb')
961        file_ctrl = ctrl.mech_control
962        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
963        self.browser.getControl(
964            name='upload_passportuploadedit').click()
965        self.assertTrue(
966            'src="http://localhost/app/students/E1000000/passport.jpg"'
967            in self.browser.contents)
968        # Student is redirected to the personal data form because
969        # personal data form is not properly filled.
970        self.browser.open(self.student_path + '/start_clearance')
971        self.assertMatches('...Personal data form is not properly filled...',
972                           self.browser.contents)
973        self.assertEqual(self.browser.url, self.student_path + '/edit_personal')
974        self.student.father_name = u'Rudolf'
975        self.browser.open(self.student_path + '/start_clearance')
976        self.assertMatches(
977            '...<h1 class="kofa-content-label">Start clearance</h1>...',
978            self.browser.contents)
979
980    def test_student_accommodation(self):
981        del self.student['accommodation']['2004']
982        self.student['studycourse'].certificate.study_mode = 'dp_ft'
983        # All beds can be assigned
984        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
985        bed1.bed_type = u'regular_male_all'
986        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
987        bed2.bed_type = u'regular_female_all'
988        notify(grok.ObjectModifiedEvent(bed1))
989        notify(grok.ObjectModifiedEvent(bed2))
990        # Login
991        self.browser.open(self.login_path)
992        self.browser.getControl(name="form.login").value = self.student_id
993        self.browser.getControl(name="form.password").value = 'spwd'
994        self.browser.getControl("Login").click()
995        # Students can book accommodation without AC ...
996        self.browser.open(self.acco_path)
997        IWorkflowInfo(self.student).fireTransition('admit')
998        self.browser.getControl("Book accommodation").click()
999        self.assertTrue(
1000            'You are not eligible to book accommodation.'
1001            in self.browser.contents)
1002        self.student['studycourse'].certificate.study_mode = 'ug_ft'
1003        self.app['hostels'].accommodation_states = [PAID]
1004        self.browser.getControl("Book accommodation").click()
1005        self.assertTrue(
1006            'You are in the wrong registration state.'
1007            in self.browser.contents)
1008        IWorkflowState(self.student).setState(PAID)
1009        self.browser.getControl("Book accommodation").click()
1010        self.assertFalse('Activation Code:' in self.browser.contents)
1011        self.browser.getControl("Create bed ticket").click()
1012        # Bed is randomly selected but, since there is only
1013        # one bed for this student, we know that
1014        self.assertEqual(self.student['accommodation']['2004'].bed_coordinates,
1015            'Hall 1, Block A, Room 101, Bed A (regular_male_all)')
1016        # Only the hall name is displayed
1017        self.assertEqual(self.student[
1018            'accommodation']['2004'].display_coordinates,
1019            'Hall 1')
1020        self.assertFalse('Hall 1, Block A, Room 101, Bed A'
1021            in self.browser.contents)
1022        self.assertTrue('<td>Hall 1</td>'
1023            in self.browser.contents)
1024        return
1025
1026    def test_handle_courses_by_lecturer(self):
1027        self.app['users'].addUser('mrslecturer', 'mrslecturersecret')
1028        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
1029        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
1030        # Add course ticket
1031        studylevel = createObject(u'waeup.StudentStudyLevel')
1032        studylevel.level = 100
1033        studylevel.level_session = 2004
1034        self.student['studycourse'].addStudentStudyLevel(
1035            self.certificate, studylevel)
1036        # Assign local Lecturer role for a certificate.
1037        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
1038        prmlocal = IPrincipalRoleManager(course)
1039        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
1040        notify(LocalRoleSetEvent(
1041            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
1042        # Login as lecturer.
1043        self.browser.open(self.login_path)
1044        self.browser.getControl(name="form.login").value = 'mrslecturer'
1045        self.browser.getControl(name="form.password").value = 'mrslecturersecret'
1046        self.browser.getControl("Login").click()
1047        self.browser.getLink("My Courses").click()
1048        self.browser.getLink("COURSE1").click()
1049        # Course results can be batch edited via the edit_courses view.
1050        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
1051        self.app['configuration'].current_academic_session = 2004
1052        IWorkflowState(self.student).setState('courses validated')
1053        self.browser.open(
1054            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
1055        self.assertTrue(
1056            'input type="text" name="scores:list"'
1057            in self.browser.contents)
1058        self.browser.getControl(name="scores:list", index=0).value = '55'
1059        self.browser.getControl(name="cas:list", index=0).value = '22'
1060        self.browser.getControl("Update scores from").click()
1061        # New score and ca has been set.
1062        self.assertEqual(
1063            self.student['studycourse']['100']['COURSE1'].score, 55)
1064        self.assertEqual(
1065            self.student['studycourse']['100']['COURSE1'].ca, 22)
1066        # Score editing has been logged.
1067        logfile = os.path.join(
1068            self.app['datacenter'].storage, 'logs', 'students.log')
1069        logcontent = open(logfile).read()
1070        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
1071                        'E1000000 100/COURSE1 score updated (55)' in logcontent)
1072        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
1073                        'E1000000 100/COURSE1 ca updated (22)' in logcontent)
1074        # Non-integer scores won't be accepted.
1075        self.browser.open(
1076            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
1077        self.assertTrue('value="55" />' in self.browser.contents)
1078        self.browser.getControl(name="scores:list", index=0).value = 'abc'
1079        self.browser.getControl("Update scores").click()
1080        self.assertTrue('Error: Score(s) and CA(s) of TESTER, Anna have not be updated.'
1081            in self.browser.contents)
1082        # Scores can be removed.
1083        self.browser.open(
1084            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
1085        self.browser.getControl(name="scores:list", index=0).value = ''
1086        self.browser.getControl("Update scores").click()
1087        self.assertEqual(
1088            self.student['studycourse']['100']['COURSE1'].score, None)
1089        logcontent = open(logfile).read()
1090        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
1091                        'E1000000 100/COURSE1 score updated (None)' in logcontent)
1092
1093
1094    def test_student_view_transcript(self):
1095        # Student cant login if their password is not set
1096        IWorkflowInfo(self.student).fireTransition('admit')
1097        self.browser.open(self.login_path)
1098        self.browser.getControl(name="form.login").value = self.student_id
1099        self.browser.getControl(name="form.password").value = 'spwd'
1100        self.browser.getControl("Login").click()
1101        self.assertMatches(
1102            '...You logged in...', self.browser.contents)
1103        # Students can view the transcript
1104        self.browser.open(self.studycourse_path)
1105        self.browser.getLink("Transcript").click()
1106        self.browser.getLink("Academic Transcript").click()
1107        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1108        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
Note: See TracBrowser for help on using the repository browser.