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

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

Remove CA column if not needed.

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