## $Id: test_browser.py 16355 2020-12-15 11:09:15Z henrik $
##
## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
import os
import shutil
import tempfile
import pytz
import grok
from StringIO import StringIO
from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
from zope.securitypolicy.interfaces import IPrincipalRoleManager
from datetime import datetime, timedelta, date
from mechanize import LinkNotFoundError, ItemNotFoundError
from hurry.workflow.interfaces import IWorkflowState
from zope.event import notify
from zope.component.hooks import setSite, clearSite
from zope.component import getUtility, createObject, queryUtility
from zope.catalog.interfaces import ICatalog
from waeup.kofa.app import University
from waeup.kofa.interfaces import VALIDATED, PAID
from waeup.kofa.students.tests.test_browser import StudentsFullSetup
from waeup.kofa.students.accommodation import BedTicket
from waeup.kofa.testing import FunctionalTestCase
from waeup.kofa.authentication import LocalRoleSetEvent
from waeup.kofa.browser.tests.test_pdf import samples_dir
from waeup.kofa.applicants.container import ApplicantsContainer
from waeup.aaue.testing import FunctionalLayer

SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')


UPLOAD_CSV_TEMPLATE = (
    'matric_number,student_id,display_fullname,level,code,level_session,'
    'score,ca,imported_ts\r\n'
    '234,E1000000,Anna Tester,100,COURSE1,2004,%s,%s,%s\r\n')

class OfficerUITests(StudentsFullSetup):
    # Tests for Student class views and pages

    layer = FunctionalLayer

    def login_as_lecturer(self):
        self.app['users'].addUser('mrslecturer', 'mrslecturerSecret1')
        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
        # Add course ticket
        studylevel = createObject(u'waeup.StudentStudyLevel')
        studylevel.level = 100
        studylevel.level_session = 2004
        self.student['studycourse'].addStudentStudyLevel(
            self.certificate, studylevel)
        # Assign local Lecturer role for a certificate.
        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
        prmlocal = IPrincipalRoleManager(course)
        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
        notify(LocalRoleSetEvent(
            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
        # Login as lecturer.
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = 'mrslecturer'
        self.browser.getControl(
            name="form.password").value = 'mrslecturerSecret1'
        self.browser.getControl("Login").click()
        # Store reused urls/paths
        self.course_url = (
            'http://localhost/app/faculties/fac1/dep1/courses/COURSE1')
        self.edit_scores_url = '%s/edit_scores' % self.course_url
        self.edit_prev_scores_url = '%s/edit_prev_scores' % self.course_url
        # Set standard parameters
        self.app['configuration'].current_academic_session = 2004
        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
        IWorkflowState(self.student).setState(VALIDATED)


    def test_gpa_calculation(self):
        studylevel = createObject(u'waeup.StudentStudyLevel')
        studylevel.level = 100
        studylevel.level_session = 2005
        self.student['studycourse'].entry_mode = 'ug_ft'
        self.student['studycourse'].addStudentStudyLevel(
            self.certificate, studylevel)
        # First course has been added automatically.
        # Set score. 
        studylevel['COURSE1'].score = 35
        studylevel['COURSE1'].ca = 20
        # GPA is 3.0.
        self.assertEqual(studylevel.gpa_params[0], 3.0)
        courseticket = createObject('waeup.CourseTicket')
        courseticket.code = 'ANYCODE'
        courseticket.title = u'Any TITLE'
        courseticket.credits = 13
        courseticket.score = 44
        courseticket.ca = 22
        courseticket.semester = 1
        courseticket.dcode = u'ANYDCODE'
        courseticket.fcode = u'ANYFCODE'
        studylevel['COURSE2'] = courseticket
        # total credits
        self.assertEqual(self.student['studycourse']['100'].gpa_params[1], 23)
        # weigheted credits = 3 * 10 + 4 * 13
        self.assertEqual(self.student['studycourse']['100'].gpa_params[2], 82.0)
        # sgpa = 82 / 23
        self.assertEqual(
            self.student['studycourse']['100'].gpa_params[0], 3.5652173913043477)
        # imported gpa values override calculated values
        studylevel.imported_gpa = 4.3
        studylevel.imported_cgpa = 5.4
        self.assertEqual(self.student['studycourse']['100'].gpa_params[0], 4.3)
        self.assertEqual(
            self.student['studycourse']['100'].cumulative_params[0], 5.4)
        self.assertEqual(self.student['studycourse']['100'].gpa, '4.30')
        self.student['studycourse'].imported_cgpa = 6.6
        self.assertEqual(
            self.student['studycourse'].getTranscriptData()[1], 6.6)
        return

    def test_grade_weight(self):
        studylevel = createObject(u'waeup.StudentStudyLevel')
        studylevel.level = 100
        studylevel.level_session = 2005
        self.course.passmark = 40
        self.student['studycourse'].entry_mode = 'ug_ft'
        self.student['studycourse'].addStudentStudyLevel(
            self.certificate, studylevel)
        studylevel['COURSE1'].score = 42
        studylevel['COURSE1'].ca = 0
        courseticket = createObject('waeup.CourseTicket')
        self.assertEqual(studylevel['COURSE1'].weight, 1)
        self.assertEqual(studylevel['COURSE1'].grade, 'E')
        self.assertEqual(studylevel['COURSE1'].weight, 1)
        self.assertEqual(studylevel['COURSE1'].grade, 'E')
        studylevel['COURSE1'].score = 45
        self.assertEqual(studylevel['COURSE1'].weight, 2)
        self.assertEqual(studylevel['COURSE1'].grade, 'D')
        return

    def test_manage_payments(self):
        # Add missing configuration data
        self.app['configuration']['2004'].gown_fee = 150.0
        self.app['configuration']['2004'].transfer_fee = 90.0
        self.app['configuration']['2004'].booking_fee = 150.0
        self.app['configuration']['2004'].maint_fee = 180.0
        self.app['configuration']['2004'].late_fee = 80.0

        # Managers can add online payment tickets
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.payments_path)
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...Wrong state...',
                           self.browser.contents)
        IWorkflowState(self.student).setState('cleared')
        self.browser.open(self.payments_path + '/addop')
        self.app['configuration']['2004'].clearance_fee = 666.0
        self.browser.getControl(name="form.p_category").value = ['clearance_incl']
        self.browser.getControl("Create ticket").click()
        self.browser.open(self.payments_path)
        ctrl = self.browser.getControl(name='val_id')
        cpt_value = ctrl.options[0]
        # School fee payment ticket can be added ...
        self.student['studycourse'].certificate.school_fee_1 = 6666.0
        self.student.nationality = u'NG'
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           self.browser.contents)
        # ... but not paid through the query_history page.
        self.browser.open(self.payments_path)
        ctrl = self.browser.getControl(name='val_id')
        sfpt_value = ctrl.options[1]
        self.student['studycourse'].entry_session = 2013
        self.student['payments'][sfpt_value].r_company = u'interswitch'
        self.browser.open(self.payments_path + '/' + sfpt_value)

        # eTranzact payments deactivated on 01/03/2019
        #self.browser.getLink("Query eTranzact History").click()
        #self.assertMatches('...alert-danger">Please pay acceptance fee first...',
        #                   self.browser.contents)
        # If clearance/acceptance fee is paid ...
        self.student['payments'][cpt_value].approveStudentPayment()
        #self.browser.getLink("Query eTranzact History").click()
        ## ... query_history page is accessible.
        #self.assertMatches(
        #    '...<h1 class="kofa-content-label">Requery eTranzact History</h1>...',
        #    self.browser.contents)

        # Managers can open school fee payment slip
        self.browser.open(self.payments_path + '/' + sfpt_value)
        self.browser.getLink("Download payment slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        # If school fee ticket is paid, the student is automatically set to
        # school fee paid...
        ticket = self.student['payments'][sfpt_value].approveStudentPayment()
        self.assertEqual(self.student.state, 'school fee paid')
        # ... no further school fee ticket can be added.
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...Wrong state...',
                           self.browser.contents)
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['late_registration']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           self.browser.contents)
        return

    def test_for_instalment_payments(self):
        configuration_1 = createObject('waeup.SessionConfiguration')
        configuration_1.academic_session = 2015
        self.app['configuration'].addSessionConfiguration(configuration_1)
        self.student['studycourse'].certificate.study_mode = 'ug_pt'
        self.student['studycourse'].certificate.school_fee_1 = 6666.0
        self.app['configuration']['2015'].union_fee = 1250.0
        self.app['configuration']['2015'].welfare_fee = 750.0
        self.student.nationality = u'NG'
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.payments_path + '/addop')
        self.assertFalse('schoolfee_1' in self.browser.contents)
        #self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
        #self.browser.getControl("Create ticket").click()
        #self.assertTrue(
        #    'Part-time students are not allowed' in self.browser.contents)
        self.student['studycourse'].certificate.study_mode = 'ug_ft'
        self.browser.open(self.payments_path + '/addop')
        self.assertTrue('schoolfee_1' in self.browser.contents)
        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
        self.browser.getControl("Create ticket").click()
        self.assertTrue('You are not allowed to pay by instalments.'
            in self.browser.contents)
        IWorkflowState(self.student).setState('cleared')
        self.student['studycourse'].entry_session = 2015
        self.student['studycourse'].current_session = 2015
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
        self.browser.getControl("Create ticket").click()
        self.assertTrue('ticket created' in self.browser.contents)
        # We can't add the 2nd instalment ticket because the
        # first one has not yet been approved.
        #self.browser.open(self.payments_path + '/addop')
        #self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
        #self.browser.getControl("Create ticket").click()
        #self.assertMatches('...1st school fee instalment has not yet been paid...',
        #                   self.browser.contents)
        # Ok, then we approve the first instalment ...
        self.browser.open(self.payments_path)
        ctrl = self.browser.getControl(name='val_id')
        p_id = ctrl.options[0]
        self.browser.open(self.payments_path + '/' + p_id + '/approve')
        # ... add the second instalment ...
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
        self.browser.getControl("Create ticket").click()
        self.assertTrue('ticket created' in self.browser.contents)
        # ... approve the second instalment ...
        self.browser.open(self.payments_path)
        ctrl = self.browser.getControl(name='val_id')
        p_id = ctrl.options[1]
        self.browser.open(self.payments_path + '/' + p_id + '/approve')
        self.assertEqual(self.student['payments'].values()[0].p_category, 'schoolfee_1')
        self.assertEqual(self.student['payments'].values()[1].p_category, 'schoolfee_2')
        # (6666-200)/2 + 1250 + 750 - 400 + 200
        self.assertEqual(self.student['payments'].values()[0].amount_auth, 5033.0)
        # (6666-200)/2 + 200
        self.assertEqual(self.student['payments'].values()[1].amount_auth, 3433.0)
        # The  two payments belong to the same session and level.
        self.assertEqual(self.student['payments'].values()[0].p_session, 2015)
        self.assertEqual(self.student['payments'].values()[0].p_level, 100)
        self.assertEqual(self.student['payments'].values()[1].p_session, 2015)
        self.assertEqual(self.student['payments'].values()[1].p_level, 100)

        # Returning student
        configuration_2 = createObject('waeup.SessionConfiguration')
        configuration_2.academic_session = 2016
        self.app['configuration'].addSessionConfiguration(configuration_2)
        self.student['studycourse'].certificate.school_fee_2 = 5666.0
        self.app['configuration']['2016'].union_fee = 1250.0
        self.app['configuration']['2016'].welfare_fee = 750.0
        self.student.father_name = u'Albert'
        IWorkflowState(self.student).setState('returning')
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
        self.browser.getControl("Create ticket").click()
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
        self.browser.getControl("Create ticket").click()
        # Student is still in the first  session.
        self.assertTrue('This type of payment' in self.browser.contents)
        self.browser.open(self.payments_path)
        ctrl = self.browser.getControl(name='val_id')
        p_id = ctrl.options[2]
        self.browser.open(self.payments_path + '/' + p_id + '/approve')
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
        self.browser.getControl("Create ticket").click()
        self.assertTrue('ticket created' in self.browser.contents)
        # (5666-200)/2 + 1250 + 750 - 400 + 200
        self.assertEqual(self.student['payments'].values()[2].amount_auth, 4533.0)
        # (5666-200)/2 + 200
        self.assertEqual(self.student['payments'].values()[3].amount_auth, 2933.0)
        # The last two payments belong to the same session and level.
        self.assertEqual(self.student['payments'].values()[2].p_session, 2016)
        self.assertEqual(self.student['payments'].values()[2].p_level, 200)
        self.assertEqual(self.student['payments'].values()[3].p_session, 2016)
        self.assertEqual(self.student['payments'].values()[3].p_level, 200)
        return

    def test_manage_payments_bypass_ac_creation(self):
        self.student['studycourse'].certificate.school_fee_1 = 6666.0
        self.student.nationality = u'NG'
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.payments_path)
        IWorkflowState(self.student).setState('cleared')
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.browser.open(self.payments_path)
        ctrl = self.browser.getControl(name='val_id')
        value = ctrl.options[0]
        self.browser.getLink(value).click()
        payment_url = self.browser.url
        logfile = os.path.join(
            self.app['datacenter'].storage, 'logs', 'students.log')
        # The ticket can be found in the payments_catalog
        cat = queryUtility(ICatalog, name='payments_catalog')
        results = list(cat.searchResults(p_state=('unpaid', 'unpaid')))
        self.assertTrue(len(results), 1)
        self.assertTrue(results[0] is self.student['payments'][value])
        # Managers can approve the payment
        self.browser.open(payment_url)
        self.browser.getLink("Approve payment").click()
        self.assertMatches('...Payment approved...',
                          self.browser.contents)
        # Approval is logged in students.log ...
        logcontent = open(logfile).read()
        self.assertTrue(
            'zope.mgr - students.browser.OnlinePaymentApproveView '
            '- E1000000 - schoolfee_incl payment approved'
            in logcontent)
        # ... and in payments.log
        logfile = os.path.join(
            self.app['datacenter'].storage, 'logs', 'payments.log')
        logcontent = open(logfile).read()
        self.assertTrue(
            '"zope.mgr",E1000000,%s,schoolfee_incl,6666.0,AP,,,,,,\n' % value
            in logcontent)
        # Student is in state school fee paid, no activation
        # code was necessary.
        self.assertEqual(self.student.state, 'school fee paid')
        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
        return

    def test_scores_csv_upload_available(self):
        # lecturers can upload a CSV file to set values.
        self.login_as_lecturer()
        # set value to change from
        self.student['studycourse']['100']['COURSE1'].score = 55
        self.app['configuration']['2004'].score_editing_enabled = ['ug_ft']
        self.browser.open(self.edit_scores_url)
        upload_ctrl = self.browser.getControl(name='uploadfile:file')
        upload_file = StringIO(UPLOAD_CSV_TEMPLATE % ('65','52','77'))
        upload_ctrl.add_file(upload_file, 'text/csv', 'myscores.csv')
        self.browser.getControl("Update editable scores from").click()
        self.assertTrue('TESTER, Anna have not be updated' in self.browser.contents)
        # values have not been changed
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].score, 55)
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].ca, None)
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].imported_ts, None)
        self.browser.open(self.edit_scores_url)
        upload_ctrl = self.browser.getControl(name='uploadfile:file')
        upload_file = StringIO(UPLOAD_CSV_TEMPLATE % ('65','22','77'))
        upload_ctrl.add_file(upload_file, 'text/csv', 'myscores.csv')
        self.browser.getControl("Update editable scores from").click()
        # values changed
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].score, 65)
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].ca, 22)
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].imported_ts, 77)

    def test_scores_previous_session(self):
        # lecturers can download a CSV file to set values.
        self.login_as_lecturer()
        self.student['studycourse']['100']['COURSE1'].score = 55
        self.browser.open(self.edit_prev_scores_url)
        self.assertTrue('No student found' in self.browser.contents)
        configuration = createObject('waeup.SessionConfiguration')
        configuration.academic_session = 2003
        self.app['configuration'].addSessionConfiguration(configuration)
        self.app['configuration']['2003'].score_editing_enabled = ['ug_ft']
        self.student['studycourse']['100'].level_session = 2003
        notify(grok.ObjectModifiedEvent(self.student['studycourse']['100']['COURSE1']))
        self.browser.open(self.edit_prev_scores_url)
        self.browser.getLink("Download csv file").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'],
                         'text/csv; charset=UTF-8')
        self.assertEqual(self.browser.contents,
            'matric_number,student_id,display_fullname,'
            'depcode,faccode,level,code,level_session,ca,score,'
            'total_score,grade,imported_ts\r\n234,E1000000,"TESTER, Anna",dep1,fac1,'
            '100,COURSE1,2003,,55,,,\r\n')
        self.browser.open(self.edit_prev_scores_url)
        upload_ctrl = self.browser.getControl(name='uploadfile:file')
        upload_file = StringIO(UPLOAD_CSV_TEMPLATE % ('65','22','77'))
        upload_ctrl.add_file(upload_file, 'text/csv', 'myscores.csv')
        self.browser.getControl("Update editable scores from").click()
        # value changed
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].score, 65)
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].ca, 22)
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].imported_ts, 77)

    def test_lecturers_can_download_course_tickets(self):
        # A course ticket slip can be downloaded
        self.login_as_lecturer()
        self.course.title = (u'Lorem ipsum dolor sit amet, consectetur '
                            u'adipisici elit, sed eiusmod tempor incidunt')
        self.student['studycourse']['100']['COURSE1'].score = 55
        self.student['studycourse']['100']['COURSE1'].ca = 11
        self.student.matric_number = u'CMS/FBM/NSG/16/28838'
        self.app['configuration']['2004'].score_editing_enabled = ['ug_ft']
        pdf_url = '%s/coursetickets.pdf' % self.course_url
        self.browser.open(pdf_url)
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(
            self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'coursetickets.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF coursetickets.pdf written to %s" % path
        # The CA column is not shown if CA is not used
        self.student['studycourse']['100']['COURSE1'].ca = 0
        self.browser.open(pdf_url)
        path = os.path.join(samples_dir(), 'coursetickets_wo_ca.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF coursetickets_wo_ca.pdf written to %s" % path

    def test_lecturers_do_only_see_selected_students(self):
        # A course ticket slip can be downloaded
        self.login_as_lecturer()
        self.student['studycourse']['100']['COURSE1'].score = 55
        self.student['studycourse']['100']['COURSE1'].ca = 11
        self.browser.open(self.edit_scores_url)
        self.assertTrue('No student found' in self.browser.contents)
        pdf_url = '%s/coursetickets.pdf' % self.course_url
        self.browser.open(pdf_url)
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(
            self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'coursetickets_filtered.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF coursetickets_filtered.pdf written to %s" % path
        self.app['configuration']['2004'].score_editing_enabled = ['ug_ft']
        self.browser.open(self.edit_scores_url)
        self.assertFalse('No student found' in self.browser.contents)
        self.assertTrue('TESTER, Anna' in self.browser.contents)

    def test_lecturers_can_download_attendance_sheet(self):
        # A course ticket slip can be downloaded
        self.course.title = (u'Lorem ipsum     dolor sit amet, consectetur     adipisici, '
                             u'sed         eiusmod tempor    incidunt ut  labore et dolore')
        self.student.firstname = u'Emmanuella Woyengifigha Mercy Onosemudiana'
        self.student.lastname = u'OYAKEMIEGBEGHA'
        self.student.matric_number = u'CMS/FBM/NSG/17/38186'
        self.login_as_lecturer()
        pdf_url = '%s/attendance.pdf' % self.course_url
        self.browser.open(pdf_url)
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(
            self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'attendance.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF attendance.pdf written to %s" % path

    def test_transcripts(self):
        studylevel = createObject(u'waeup.StudentStudyLevel')
        studylevel.level = 100
        studylevel.level_session = 2005
        self.student['studycourse'].entry_mode = 'ug_ft'
        self.student['studycourse'].addStudentStudyLevel(
            self.certificate, studylevel)
        studylevel2 = createObject(u'waeup.StudentStudyLevel')
        studylevel2.level = 200
        studylevel2.level_session = 2006
        self.student['studycourse']['100']['COURSE1'].score = 33 # no carry-over!
        self.student['studycourse']['100']['COURSE1'].ca = 22
        self.student['studycourse'].addStudentStudyLevel(
            self.certificate, studylevel2)
        # Add second course (COURSE has been added automatically)
        courseticket = createObject('waeup.CourseTicket')
        courseticket.code = 'ANYCODE'
        courseticket.title = u'Any TITLE'
        courseticket.credits = 13
        courseticket.score = 55
        courseticket.ca = 11
        courseticket.semester = 1
        courseticket.dcode = u'ANYDCODE'
        courseticket.fcode = u'ANYFCODE'
        self.student['studycourse']['200']['COURSE2'] = courseticket
        self.assertEqual(self.student['studycourse']['100'].gpa_params_rectified[0], 3.0)
        self.assertEqual(self.student['studycourse']['200'].gpa_params_rectified[0], 4.0)
        # Get transcript data
        td = self.student['studycourse'].getTranscriptData()
        self.assertEqual(td[0][0]['level_key'], '100')
        self.assertEqual(td[0][0]['sgpa'], 3.0)
        self.assertEqual(td[0][0]['level'].level, 100)
        self.assertEqual(td[0][0]['level'].level_session, 2005)
        self.assertEqual(td[0][0]['tickets_1'][0].code, 'COURSE1')
        self.assertEqual(td[0][1]['level_key'], '200')
        self.assertEqual(td[0][1]['sgpa'], 4.0)
        self.assertEqual(td[0][1]['level'].level, 200)
        self.assertEqual(td[0][1]['level'].level_session, 2006)
        self.assertEqual(td[0][1]['tickets_1'][0].code, 'ANYCODE')
        self.assertEqual(td[1], 3.5652173913043477)
        # Set Officer 1
        self.app['faculties']['fac1']['dep1'].officer_1 = u'Transcript Boss'
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.student_path + '/studycourse/transcript')
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertTrue('Transcript' in self.browser.contents)
        # Officers can open the pdf transcript
        self.browser.open(self.student_path + '/studycourse/transcript.pdf')
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'transcript.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF transcript.pdf written to %s" % path

    def test_payment_disabled(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.payments_path)
        IWorkflowState(self.student).setState('cleared')
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...', self.browser.contents)
        self.app['configuration']['2004'].payment_disabled = ['sf_all']
        self.browser.open(self.payments_path)
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...This category of payments has been disabled...',
                           self.browser.contents)

        self.app['configuration']['2004'].payment_disabled = ['sf_ug_pt']
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...', self.browser.contents)
        self.certificate.study_mode = 'ug_pt'
        self.browser.open(self.payments_path)
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...This category of payments has been disabled...',
                           self.browser.contents)

        self.app['configuration']['2004'].payment_disabled = ['sf_pg']
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...', self.browser.contents)
        self.certificate.study_mode = 'special_pg_ft'
        self.browser.open(self.payments_path)
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...This category of payments has been disabled...',
                           self.browser.contents)
        return

class StudentUITests(StudentsFullSetup):
    """Tests for customized student class views and pages
    """

    layer = FunctionalLayer

    def setUp(self):
        super(StudentUITests, self).setUp()

        bedticket = BedTicket()
        bedticket.booking_session = 2004
        bedticket.bed_type = u'any bed type'
        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
        bedticket.bed_coordinates = u'My bed coordinates'
        self.student['accommodation'].addBedTicket(bedticket)

    def test_maintenance_fee_payment(self):
        self.certificate.study_mode = 'ug_ft'
        self.student['studycourse'].entry_session = 2013
        self.student.nationality = u'NG'
        IWorkflowState(self.student).setState('cleared')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.open(self.student_path + '/payments')
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['hostel_maintenance']
        self.browser.getControl("Create ticket").click()
        self.assertTrue('ticket created' in self.browser.contents)
        value = self.student['payments'].keys()[0]
        self.browser.getLink(value).click()
        self.assertTrue('<span>My bed coordinates</span>' in self.browser.contents)
        self.assertEqual(self.student['payments'][value].amount_auth, 876.0)
        return

    def test_student_schoolfee_payments(self):
        configuration_1 = createObject('waeup.SessionConfiguration')
        configuration_1.academic_session = 2018
        self.app['configuration'].addSessionConfiguration(configuration_1)
        self.certificate.study_mode = 'ug_ft'
        self.student['studycourse'].entry_session = 2018
        self.student['studycourse'].current_session = 2018
        self.student['studycourse'].entry_mode = 'ug_ft'
        self.student['studycourse'].certificate.school_fee_1 = 50200.0
        self.app['configuration']['2018'].union_fee = 1200.0
        self.app['configuration']['2018'].welfare_fee = 700.0
        #self.app['configuration']['2017'].id_card_fee = 300.0
        self.app['configuration']['2018'].sports_fee = 300.0
        self.app['configuration']['2018'].library_fee = 300.0
        self.student.nationality = u'NG'
        # Login
        IWorkflowState(self.student).setState('cleared')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        # Test school fee payments
        self.browser.open(self.student_path + '/payments')
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
        self.browser.getControl("Create ticket").click()
        self.assertTrue('ticket created' in self.browser.contents)
        value = self.student['payments'].keys()[0]
        self.student['payments'][value].p_state = 'paid'
        self.browser.getLink(value).click()
        self.assertTrue('Amount Authorized' in self.browser.contents)
        # 50200 + 1200 + 700 + 300 + 300- 800 = 51900
        self.assertEqual(self.student['payments'][value].amount_auth, 51900.0)
        self.student['payments'][value].r_company = u'interswitch'
        self.browser.getLink("Download").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'payment_slip.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF payment_slip.pdf written to %s" % path
        # Another school fee payment cannot be added
        self.student['payments'][value].approve()
        self.browser.open(self.student_path + '/payments')
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl(name="form.p_category").value = ['schoolfee']
        self.browser.getControl("Create ticket").click()
        self.assertTrue(
            'You must choose a payment which includes additional fees'
            in self.browser.contents)
        return

    def test_late_registration(self):
        delta = timedelta(days=10)
        self.app['configuration'][
            '2004'].coursereg_deadline = datetime.now(pytz.utc) - delta
        IWorkflowState(self.student).setState('school fee paid')
        # Current session is 2004. Here we test course registration for
        # returning students.
        self.student['studycourse'].entry_session = 2003
        self.student['studycourse'].current_session = 2016
        # Login
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        # Make restitution fee payment
        # Ivie: The restitution was only for returning students of 2016/2017.
        # Hence, it is only valid for 2016 payment session returning students.
        configuration = createObject('waeup.SessionConfiguration')
        configuration.academic_session = 2016
        self.app['configuration'].addSessionConfiguration(configuration)
        self.app['configuration']['2016'].restitution_fee = 9999.0
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['restitution']
        self.browser.getControl("Create ticket").click()
        self.student['payments'].values()[0].approveStudentPayment()
        # Make late registration fee payment
        self.student['studycourse'].current_session = 2004
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['late_registration']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           self.browser.contents)
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.assertMatches('...Add current level 100 (Year 1)...',
                           self.browser.contents)
        self.browser.getControl("Create course list now").click()
        self.student['studycourse']['100']['COURSE1'].score = 67
        self.browser.getLink("100").click()
        # Course results can't be seen
        self.assertFalse('<td>67</td>' in self.browser.contents)
        self.browser.getLink("Edit course list").click()
        self.assertFalse('<td>67</td>' in self.browser.contents)
        self.app['configuration']['2004'].late_registration_fee = 0.0
        self.browser.getControl("Register course list").click()
        self.assertTrue('Course registration has been disabled.' in self.browser.contents)
        self.app['configuration']['2004'].late_registration_fee = 345.0
        self.browser.getControl("Register course list").click()
        self.assertTrue('Course registration has ended. Please pay' in self.browser.contents)
        self.student['payments'].values()[1].approve()
        self.browser.getControl("Register course list").click()
        self.assertTrue('Course list has been registered' in self.browser.contents)
        self.assertEqual(self.student.state, 'courses registered')
        # Reset student and check if fresh students are always allowed to
        # register courses.
        #self.student['studycourse'].entry_session = 2004
        #del self.student['payments'][self.student['payments'].keys()[1]]
        #IWorkflowState(self.student).setState('school fee paid')
        #self.browser.open(self.studycourse_path + '/100/edit')
        #self.browser.getControl("Register course list").click()
        #self.assertTrue('Course list has been registered' in self.browser.contents)
        return


    def deactivated_test_student_course_registration(self):
        # Add more courses
        self.course2 = createObject('waeup.Course')
        self.course2.code = 'COURSE2'
        self.course2.semester = 2
        self.course2.credits = 10
        self.course2.passmark = 40
        self.app['faculties']['fac1']['dep1'].courses.addCourse(
            self.course2)
        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
            self.course2, level=100)
        self.course3 = createObject('waeup.Course')
        self.course3.code = 'COURSE3'
        self.course3.semester = 3
        self.course3.credits = 10
        self.course3.passmark = 40
        self.app['faculties']['fac1']['dep1'].courses.addCourse(
            self.course3)
        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
            self.course3, level=100)

        # Login as student
        self.browser.open(self.login_path)
        IWorkflowState(self.student).setState('school fee paid')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        # Students can add the current study level
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.assertMatches('...Add current level 100 (Year 1)...',
                           self.browser.contents)
        self.browser.getControl("Create course list now").click()
        # Student has not paid second instalment, therefore a level
        # with two course ticket was created (semester 1 and combined)
        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
        self.browser.getLink("100").click()
        self.browser.getLink("Edit course list").click()
        self.browser.getControl("Add course ticket").click()
        # Student can't add second semester course
        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
        self.assertFalse('<option value="COURSE2">' in self.browser.contents)

        # Let's remove level and see what happens after 2nd instalment payment
        del(self.student['studycourse']['100'])
        payment2 = createObject('waeup.StudentOnlinePayment')
        payment2.p_category = u'schoolfee_2'
        payment2.p_session = self.student.current_session
        self.student['payments']['anykey'] = payment2
        self.browser.open(self.studycourse_path)
        self.browser.getLink("Add course list").click()
        self.browser.getControl("Create course list now").click()
        # Still only 2 tickets have been created since payment ticket
        # was not paid
        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 2)
        payment2.p_state = u'paid'
        del(self.student['studycourse']['100'])
        self.browser.open(self.studycourse_path)
        self.browser.getLink("Add course list").click()
        self.browser.getControl("Create course list now").click()
        # Now 2nd semester course has been added
        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 3)
        # Student can add second semester course
        self.browser.getLink("100").click()
        self.browser.getLink("Edit course list").click()
        self.browser.getControl("Add course ticket").click()
        self.assertTrue('<option value="COURSE1">' in self.browser.contents)
        self.assertTrue('<option value="COURSE2">' in self.browser.contents)
        self.assertTrue('<option value="COURSE3">' in self.browser.contents)
        return

    def test_set_matric_number(self):
        #payment = createObject('waeup.StudentOnlinePayment')
        #payment.p_category = u'concessional'
        #payment.p_id = u'anyid'
        #payment.p_state = u'paid'
        #self.student['payments']['anykey'] = payment
        # Login as student
        self.browser.open(self.login_path)
        IWorkflowState(self.student).setState('school fee paid')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.assertRaises(
            LinkNotFoundError,
            self.browser.getLink, 'Get Matriculation Number')
        self.student.matric_number = None
        site = grok.getSite()
        site['configuration'].next_matric_integer = 1
        self.student['studycourse'].certificate.study_mode = 'ug_pt'
        self.browser.open(self.student_path)
        self.assertRaises(
            LinkNotFoundError,
            self.browser.getLink, 'Download matriculation number slip')
        self.browser.getLink("Get Matriculation Number").click()
        self.assertTrue('Matriculation number PTP/fac1/dep1/04/00001 assigned.'
            in self.browser.contents)
        self.assertEqual(self.student.matric_number, 'PTP/fac1/dep1/04/00001')
        self.assertRaises(
            LinkNotFoundError,
            self.browser.getLink, 'Get Matriculation Number')
        # Setting matric number is logged.
        logfile = os.path.join(
            self.app['datacenter'].storage, 'logs', 'students.log')
        logcontent = open(logfile).read()
        self.assertTrue('E1000000 - waeup.aaue.students.browser.StudentGetMatricNumberPage - '
                        'E1000000 - PTP/fac1/dep1/04/00001 assigned' in logcontent)
        # Matric Number Slip can be downloaded
        self.browser.getLink("Download matriculation number slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'matric_number_slip.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF matric_number_slip.pdf written to %s" % path
        return

    def test_personal_data_slip(self):
        # Login as student
        self.browser.open(self.login_path)
        IWorkflowState(self.student).setState('school fee paid')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.getLink("Personal Data").click()
        self.assertRaises(
            LinkNotFoundError,
            self.browser.getLink, 'Download personal data slip')
        self.student.father_name = u'Rudolf'
        self.browser.open(self.personal_path)
        self.browser.getLink("Download personal data slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'personal_data_slip.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF personal_data_slip.pdf written to %s" % path
        return

    def test_student_course_registration(self):
        IWorkflowState(self.student).setState('school fee paid')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        # Now students can add the current study level
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.assertMatches('...Add current level 100 (Year 1)...',
                           self.browser.contents)
        self.browser.getControl("Create course list now").click()
        # Students can't open the customized pdf course registration slip
        self.browser.open(
            self.student_path + '/studycourse/100/course_registration_slip.pdf')
        self.assertTrue('Forbidden' in self.browser.contents)
        # They can open slips from the previous session ...
        self.student['studycourse'].current_level = 200
        self.browser.open(self.student_path + '/studycourse/100')
        self.browser.getLink("Download course registration slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        # or if they have registered their course list
        self.student['studycourse'].current_level = 200
        IWorkflowState(self.student).setState('courses registered')
        self.browser.open(self.student_path + '/studycourse/100')
        self.browser.getLink("Download course registration slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'ft_course_registration_slip.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF ft_course_registration_slip.pdf written to %s" % path

        self.certificate.study_mode = 'ug_pt'
        self.browser.open(self.student_path + '/studycourse/100')
        self.browser.getLink("Download course registration slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'pt_course_registration_slip.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF pt_course_registration_slip.pdf written to %s" % path

        self.certificate.study_mode = 'special_pg_ft'
        self.student.matric_number = u'AAU/SPS/FLW/LAW/15/PHD/09504'
        self.browser.open(self.student_path + '/studycourse/100')
        self.browser.getLink("Download course registration slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'pg_course_registration_slip.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF pg_course_registration_slip.pdf written to %s" % path

        # Students cant' view scores, cas and grades.
        self.browser.open(self.student_path + '/studycourse/100')
        self.assertFalse('Score' in self.browser.contents)
        self.assertFalse('CA' in self.browser.contents)
        self.assertFalse('Grade' in self.browser.contents)
        self.browser.getLink("COURSE1").click()
        self.browser.open(self.student_path + '/studycourse/100')
        self.assertFalse('Score' in self.browser.contents)
        self.assertFalse('CA' in self.browser.contents)
        self.assertFalse('Grade' in self.browser.contents)

    def test_student_2nd_semester_course_registration(self):
        IWorkflowState(self.student).setState('school fee paid')
        self.student['studycourse'].entry_session = 2015
        self.course.semester = 2
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.browser.getControl("Create course list now").click()
        self.assertFalse('COURSE1' in self.browser.contents)
        # 2nd semester tickets can't be added manually
        self.browser.getLink("Edit course list").click()
        self.browser.getLink("here").click()
        self.browser.getControl(name="form.course").value = ['COURSE1']
        self.browser.getControl("Add course ticket").click()
        self.assertTrue(
            'COURSE1 is a 2nd semester course which can only '
            'be added if school fees have been fully paid.'
            in self.browser.contents)
        # 2nd instalment has to be paid first
        self.certificate.school_fee_3 = 678.0
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_2']
        self.browser.getControl("Create ticket").click()
        self.student['payments'].values()[0].approve()
        self.browser.open(self.studycourse_path + '/100/ctadd')
        self.browser.getControl(name="form.course").value = ['COURSE1']
        self.browser.getControl("Add course ticket").click()
        self.assertTrue('Successfully added COURSE1' in self.browser.contents)
        return

    def test_student_GST_registration(self):
        configuration_1 = createObject('waeup.SessionConfiguration')
        configuration_1.academic_session = 2016
        configuration_1.gst_registration_1_fee = 3333.0
        configuration_1.gst_text_book_1_fee = 4444.0
        configuration_1.gst_text_book_0_fee = 2222.0
        self.app['configuration'].addSessionConfiguration(configuration_1)
        course = createObject('waeup.Course')
        course.code = 'GST101'
        course.semester = 1
        course.credits = 10
        course.passmark = 40
        self.app['faculties']['fac1']['dep1'].courses.addCourse(
            course)
        self.app['faculties']['fac1']['dep1'].certificates[
            'CERT1'].addCertCourse(course, level=100)
        IWorkflowState(self.student).setState('school fee paid')
        self.student['studycourse'].entry_session = 2016
        self.student['studycourse'].current_session = 2016
        self.course.semester = 2
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.browser.getControl("Create course list now").click()
        self.assertFalse('GST101' in self.browser.contents)
        # GST101 tickets can't be added manually
        self.browser.getLink("Edit course list").click()
        self.browser.getLink("here").click()
        self.browser.getControl(name="form.course").value = ['GST101']
        self.browser.getControl("Add course ticket").click()
        self.assertTrue(
            'GST101 can only be added if both registration fee and text'
            in self.browser.contents)
        # GST fees have to be paid first
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['gst_registration_1']
        self.browser.getControl("Create ticket").click()
        self.student['payments'].values()[0].approve()
        self.browser.open(self.studycourse_path + '/100/ctadd')
        self.browser.getControl(name="form.course").value = ['GST101']
        self.browser.getControl("Add course ticket").click()
        self.assertTrue(
            'GST101 can only be added if both registration fee and text'
            in self.browser.contents)
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['gst_text_book_0']
        self.browser.getControl("Create ticket").click()
        self.student['payments'].values()[1].approve()
        self.browser.open(self.studycourse_path + '/100/ctadd')
        self.browser.getControl(name="form.course").value = ['GST101']
        self.browser.getControl("Add course ticket").click()
        self.assertTrue('Successfully added GST101' in self.browser.contents)
        return

    def test_course_registration_forbidden(self):
        IWorkflowState(self.student).setState('school fee paid')
        self.student['studycourse'].entry_session = 2016
        self.student['studycourse'].current_session = 2016
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.browser.getControl("Create course list now").click()
        self.browser.getLink("Edit course list").click()
        self.browser.getControl("Register course list").click()
        #self.assertTrue('Please pay faculty and departmental dues first'
        #    in self.browser.contents)
        #configuration_1 = createObject('waeup.SessionConfiguration')
        #configuration_1.academic_session = 2016
        #configuration_1.fac_dep_fee = 9999.0
        #self.app['configuration'].addSessionConfiguration(configuration_1)
        #self.browser.open(self.payments_path + '/addop')
        #self.browser.getControl(name="form.p_category").value = ['fac_dep']
        #self.browser.getControl("Create ticket").click()
        #self.student['payments'].values()[0].approveStudentPayment()
        #self.browser.open(self.studycourse_path + '/100/edit')
        #self.browser.getControl("Register course list").click()

        ######################################################
        # Temporarily disabled ug_ft course registration
        #self.assertTrue('Course registration has been disabled'
        #    in self.browser.contents)
        #return
        ######################################################

        self.assertTrue('Course list has been registered'
            in self.browser.contents)
        return

    def test_course_registration_forbidden_2(self):
        IWorkflowState(self.student).setState('school fee paid')
        self.student['studycourse'].entry_session = 2004
        self.student['studycourse'].current_session = 2016
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.browser.getControl("Create course list now").click()
        self.browser.getLink("Edit course list").click()
        self.browser.getControl("Register course list").click()

        ######################################################
        # Temporarily disabled ug_ft course registration
        #self.assertTrue('Course registration has been disabled'
        #    in self.browser.contents)
        #return
        ######################################################

        self.assertTrue('Please pay restitution fee first'
            in self.browser.contents)
        configuration = createObject('waeup.SessionConfiguration')
        configuration.academic_session = 2016
        self.app['configuration'].addSessionConfiguration(configuration)
        self.app['configuration']['2016'].restitution_fee = 9999.0
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['restitution']
        self.browser.getControl("Create ticket").click()
        self.student['payments'].values()[0].approveStudentPayment()
        self.browser.open(self.studycourse_path + '/100/edit')
        self.browser.getControl("Register course list").click()
        self.assertTrue('Course list has been registered'
            in self.browser.contents)
        return

    def test_student_access_course_results(self):
        IWorkflowState(self.student).setState('school fee paid')
        self.student['studycourse'].entry_session = 2004
        self.student['studycourse'].current_session = 2004
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.browser.getControl("Create course list now").click()
        self.assertFalse('Score' in self.browser.contents)
        IWorkflowState(self.student).setState('returning')
        self.browser.open(self.studycourse_path + '/100')
        self.assertFalse('Score' in self.browser.contents)
        self.app['configuration']['2004'].show_results = ['ug_ft']
        self.browser.open(self.studycourse_path + '/100')
        self.assertTrue('Score' in self.browser.contents)
        return

    def test_repair_course_list(self):
        IWorkflowState(self.student).setState('school fee paid')
        self.student['studycourse'].entry_session = 2016
        self.student['studycourse'].current_session = 2016
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.browser.getControl("Create course list now").click()
        self.assertTrue('Edit course list' in self.browser.contents)
        self.assertFalse('Repair course list' in self.browser.contents)
        self.student['studycourse'].current_level = 200
        self.browser.open(self.studycourse_path + '/100')
        self.assertFalse('Edit course list' in self.browser.contents)
        self.assertFalse('Repair course list' in self.browser.contents)
        configuration = createObject('waeup.SessionConfiguration')
        configuration.academic_session = 2016
        self.app['configuration'].addSessionConfiguration(configuration)
        self.app['configuration']['2016'].studylevel_repair_enabled = True
        self.browser.open(self.studycourse_path + '/100')
        self.assertFalse('Edit course list' in self.browser.contents)
        self.assertTrue('Repair course list' in self.browser.contents)
        self.browser.getLink("Repair").click()
        self.assertEqual(self.browser.url, self.studycourse_path + '/100/repair')
        self.assertTrue('Repair course list of 100' in self.browser.contents)
        return

    def test_student_clearance(self):
        # Student cant login if their password is not set
        IWorkflowInfo(self.student).fireTransition('admit')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.assertMatches(
            '...You logged in...', self.browser.contents)
        # Admitted student can upload a passport picture
        self.browser.open(self.student_path + '/change_portrait')
        ctrl = self.browser.getControl(name='passportuploadedit')
        file_obj = open(SAMPLE_IMAGE, 'rb')
        file_ctrl = ctrl.mech_control
        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
        self.browser.getControl(
            name='upload_passportuploadedit').click()
        self.assertTrue(
            'src="http://localhost/app/students/E1000000/passport.jpg"'
            in self.browser.contents)
        # Student is redirected to the personal data form because
        # personal data form is not properly filled.
        self.browser.open(self.student_path + '/start_clearance')
        self.assertMatches('...Personal data form is not properly filled...',
                           self.browser.contents)
        self.assertEqual(self.browser.url, self.student_path + '/edit_personal')
        self.student.father_name = u'Rudolf'
        self.browser.open(self.student_path + '/start_clearance')
        self.assertMatches(
            '...<h1 class="kofa-content-label">Start clearance</h1>...',
            self.browser.contents)

    def test_student_accommodation(self):
        del self.student['accommodation']['2004']
        self.student['studycourse'].certificate.study_mode = 'dp_ft'
        # All beds can be assigned
        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
        bed1.bed_type = u'regular_male_all'
        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
        bed2.bed_type = u'regular_female_all'
        notify(grok.ObjectModifiedEvent(bed1))
        notify(grok.ObjectModifiedEvent(bed2))
        # Login
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        # Students can book accommodation without AC ...
        self.browser.open(self.acco_path)
        IWorkflowInfo(self.student).fireTransition('admit')
        self.browser.getControl("Book accommodation").click()
        self.assertTrue(
            'You are not eligible to book accommodation.'
            in self.browser.contents)
        self.student['studycourse'].certificate.study_mode = 'ug_ft'
        self.app['hostels'].accommodation_states = [PAID]
        self.browser.getControl("Book accommodation").click()
        self.assertTrue(
            'You are in the wrong registration state.'
            in self.browser.contents)
        IWorkflowState(self.student).setState(PAID)
        self.browser.getControl("Book accommodation").click()
        self.assertFalse('Activation Code:' in self.browser.contents)
        self.browser.getControl("Create bed ticket").click()
        # Bed is randomly selected but, since there is only
        # one bed for this student, we know that
        self.assertEqual(self.student['accommodation']['2004'].bed_coordinates,
            'Hall 1, Block A, Room 101, Bed A (regular_male_all)')
        # Only the hall name is displayed
        self.assertEqual(self.student[
            'accommodation']['2004'].display_coordinates,
            'Hall 1')
        self.assertFalse('Hall 1, Block A, Room 101, Bed A'
            in self.browser.contents)
        self.assertTrue('<td>Hall 1</td>'
            in self.browser.contents)
        return

    def test_handle_courses_by_lecturer(self):
        self.app['users'].addUser('mrslecturer', 'mrslecturerSecret1')
        self.app['users']['mrslecturer'].email = 'mrslecturer@foo.ng'
        self.app['users']['mrslecturer'].title = u'Mercedes Benz'
        # Add course ticket
        studylevel = createObject(u'waeup.StudentStudyLevel')
        studylevel.level = 100
        studylevel.level_session = 2004
        self.student['studycourse'].addStudentStudyLevel(
            self.certificate, studylevel)
        # Assign local Lecturer role for a certificate.
        course = self.app['faculties']['fac1']['dep1'].courses['COURSE1']
        prmlocal = IPrincipalRoleManager(course)
        prmlocal.assignRoleToPrincipal('waeup.local.Lecturer', 'mrslecturer')
        notify(LocalRoleSetEvent(
            course, 'waeup.local.Lecturer', 'mrslecturer', granted=True))
        # Login as lecturer.
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = 'mrslecturer'
        self.browser.getControl(name="form.password").value = 'mrslecturerSecret1'
        self.browser.getControl("Login").click()
        self.browser.getLink("My Courses").click()
        self.browser.getLink("COURSE1").click()
        # Course results can be batch edited via the edit_courses view.
        self.app['faculties']['fac1']['dep1'].score_editing_disabled = False
        self.app['configuration'].current_academic_session = 2004
        self.app['configuration']['2004'].score_editing_enabled = ['ug_ft']
        IWorkflowState(self.student).setState('courses validated')
        self.browser.open(
            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
        self.assertTrue(
            'input type="text" name="scores:list"'
            in self.browser.contents)
        self.browser.getControl(name="scores:list", index=0).value = '55'
        self.browser.getControl(name="cas:list", index=0).value = '22'
        self.browser.getControl("Update scores from").click()
        # New score and ca has been set.
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].score, 55)
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].ca, 22)
        # Score editing has been logged.
        logfile = os.path.join(
            self.app['datacenter'].storage, 'logs', 'students.log')
        logcontent = open(logfile).read()
        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
                        'E1000000 100/COURSE1 score updated (55)' in logcontent)
        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
                        'E1000000 100/COURSE1 ca updated (22)' in logcontent)
        # Non-integer scores won't be accepted.
        self.browser.open(
            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
        self.assertTrue('value="55" />' in self.browser.contents)
        self.browser.getControl(name="scores:list", index=0).value = 'abc'
        self.browser.getControl("Update scores").click()
        self.assertTrue('Error: Score(s), CA(s) and Imported TS(s) of TESTER, Anna have not be updated.'
            in self.browser.contents)
        # Scores can be removed.
        self.browser.open(
            "http://localhost/app/faculties/fac1/dep1/courses/COURSE1/edit_scores")
        self.browser.getControl(name="scores:list", index=0).value = ''
        self.browser.getControl("Update scores").click()
        self.assertEqual(
            self.student['studycourse']['100']['COURSE1'].score, None)
        logcontent = open(logfile).read()
        self.assertTrue('mrslecturer - waeup.aaue.students.browser.CustomEditScoresPage - '
                        'E1000000 100/COURSE1 score updated (None)' in logcontent)


    def disabled_test_student_view_transcript(self):
        # Student cant login if their password is not set
        IWorkflowInfo(self.student).fireTransition('admit')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.assertMatches(
            '...You logged in...', self.browser.contents)
        # Students can view the transcript
        self.browser.open(self.studycourse_path)
        self.browser.getLink("Transcript").click()
        self.browser.getLink("Academic Transcript").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')

    def test_alumni_request_pw(self):
        # Add an applicants container
        applicantscontainer = ApplicantsContainer()
        applicantscontainer.code = u'trans2017'
        applicantscontainer.prefix = 'trans'
        applicantscontainer.year = 2017
        applicantscontainer.title = u'This is the trans2017 container'
        applicantscontainer.application_category = 'no'
        applicantscontainer.mode = 'create'
        applicantscontainer.strict_deadline = True
        delta = timedelta(days=10)
        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
        self.app['applicants']['trans2017'] = applicantscontainer
        self.applicantscontainer = self.app['applicants']['trans2017']
        # Student with wrong number can't be found.
        # Applicant is redirected to application section.
        self.browser.open('http://localhost/app/alumni_requestpw')
        self.browser.getControl(name="form.lastname").value = 'Tester'
        self.browser.getControl(name="form.number").value = 'anynumber'
        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
        self.browser.getControl("Send login credentials").click()
        self.assertTrue('No student record found.'
            in self.browser.contents)
        self.assertEqual(self.browser.url,
            'http://localhost/app/applicants/trans2017/register')

    def test_student_course_registration_outstanding(self):
        self.course = createObject('waeup.Course')
        self.course.code = 'COURSE2'
        self.course.semester = 1
        self.course.credits = 39
        self.course.passmark = 40
        self.app['faculties']['fac1']['dep1'].courses.addCourse(
            self.course)
        IWorkflowState(self.student).setState('school fee paid')
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.open(self.student_path + '/studycourse/add')
        self.browser.getControl("Create course list now").click()
        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 1)
        self.student['studycourse'].current_level = 200
        self.browser.getLink("Study Course").click()
        self.browser.getLink("Add course list").click()
        self.assertMatches('...Add current level 200 (Year 2)...',
                           self.browser.contents)
        self.browser.getControl("Create course list now").click()
        self.browser.getLink("200").click()
        self.browser.getLink("Edit course list").click()
        self.browser.getLink("here").click()
        self.browser.getControl(name="form.course").value = ['COURSE2']
        self.browser.getControl("Add course ticket").click()
        # Carryover COURSE1 in level 200 already has 10 credits
        self.assertMatches(
            '...Maximum credits exceeded...', self.browser.contents)
        # If COURSE1 is outstanding, its credits won't be considered
        self.student['studycourse']['200']['COURSE1'].outstanding = True
        self.browser.getControl("Add course ticket").click()
        # Corresponding certificate course is missing
        self.assertTrue(
            'COURSE2 is not part of the CERT1 curriculum.'
            in self.browser.contents)
        self.app['faculties']['fac1']['dep1'].certificates[
            'CERT1'].addCertCourse(self.course, level=100)
        self.browser.getControl("Add course ticket").click()
        self.assertTrue(
            'Successfully added COURSE2' in self.browser.contents)
        return

    def test_examination_schedule_slip(self):
        self.student.flash_notice = u'My Examination Date'
        self.browser.open(self.login_path)
        self.browser.getControl(name="form.login").value = self.student_id
        self.browser.getControl(name="form.password").value = 'spwd'
        self.browser.getControl("Login").click()
        self.browser.open(self.student_path)
        self.browser.getLink("Download examination schedule slip").click()
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
        path = os.path.join(samples_dir(), 'examination_schedule_slip.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF examination_schedule_slip.pdf written to %s" % path
        # If flash_notice does not contain exam' the button does not show up.
        self.student.flash_notice = u'anything'
        self.browser.open(self.student_path)
        self.assertFalse('examination schedule slip' in self.browser.contents)