## $Id: test_browser.py 11631 2014-05-13 07:16:45Z 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 grok
from mechanize import LinkNotFoundError
from hurry.workflow.interfaces import IWorkflowState
from zope.component.hooks import setSite, clearSite
from zope.component import getUtility, createObject
from waeup.kofa.app import University
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.browser.tests.test_pdf import samples_dir
from waeup.aaue.testing import FunctionalLayer


class StudentProcessorTest(FunctionalTestCase):
    """Perform some batching tests.
    """

    layer = FunctionalLayer

    def setUp(self):
        super(StudentProcessorTest, self).setUp()
        # Setup a sample site for each test
        app = University()
        self.dc_root = tempfile.mkdtemp()
        app['datacenter'].setStoragePath(self.dc_root)

        # Prepopulate the ZODB...
        self.getRootFolder()['app'] = app
        # we add the site immediately after creation to the
        # ZODB. Catalogs and other local utilities are not setup
        # before that step.
        self.app = self.getRootFolder()['app']
        # Set site here. Some of the following setup code might need
        # to access grok.getSite() and should get our new app then
        setSite(app)


    def tearDown(self):
        super(StudentProcessorTest, self).tearDown()
        shutil.rmtree(self.workdir)
        shutil.rmtree(self.dc_root)
        clearSite()
        return

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

    layer = FunctionalLayer

    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 = 55
        # 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 = 66
        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.565)
        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_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']
        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.browser.getControl("Create ticket").click()
        self.assertMatches('...Amount could not be determined...',
                           self.browser.contents)
        self.app['configuration']['2004'].school_fee_1 = 6666.0
        #self.browser.getControl(name="form.p_category").value = ['schoolfee']
        # Accepotance fee must be paid first
        #self.browser.getControl("Create ticket").click()
        #self.assertMatches('...Please pay acceptance fee first...',
        #                   self.browser.contents)
        self.app['configuration']['2004'].clearance_fee = 666.0
        self.browser.getControl(name="form.p_category").value = ['clearance']
        self.browser.getControl("Create ticket").click()
        ctrl = self.browser.getControl(name='val_id')
        cpt_value = ctrl.options[0]
        # School fee payment ticket can be added ...
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           self.browser.contents)
        # ... but not paid through the query_history page.
        ctrl = self.browser.getControl(name='val_id')
        sfpt_value = ctrl.options[1]
        self.student['studycourse'].entry_session = 2013
        self.browser.open(self.payments_path + '/' + sfpt_value)
        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 ...
        ticket = self.student['payments'][sfpt_value].approveStudentPayment()
        # ... no further school fee ticket can be added.
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...This type of payment has already been made...',
                           self.browser.contents)

    def deactivated_test_for_instalment_payments(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.payments_path)
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           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.assertMatches('...ticket created...',
                           self.browser.contents)
        # ... approve the second instalment ...
        ctrl = self.browser.getControl(name='val_id')
        p_id = ctrl.options[1]
        self.browser.open(self.payments_path + '/' + p_id + '/approve')
        # ... and finally add the 1st instalment for the next session
        # provided that student is returning.
        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.assertMatches('...Session configuration object is not...',
                           self.browser.contents)
        # Uups, we forgot to add a session configuration for next session
        configuration = createObject('waeup.SessionConfiguration')
        configuration.academic_session = 2005
        self.app['configuration'].addSessionConfiguration(configuration)
        self.app['configuration']['2005'].school_base = 7777.0
        self.browser.open(self.payments_path + '/addop')
        self.browser.getControl(name="form.p_category").value = ['schoolfee_1']
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...ticket created...',
                           self.browser.contents)
        # If the session configuration doesn't exist an error message will
        # be shown. No other requirement is being checked.
        del self.app['configuration']['2004']
        self.browser.open(self.payments_path)
        self.browser.getLink("Add current session payment ticket").click()
        self.browser.getControl("Create ticket").click()
        self.assertMatches('...Session configuration object is not...',
                           self.browser.contents)

    def test_student_payments(self):
        # Login
        IWorkflowState(self.student).setState('returning')
        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.assertTrue(
          'Add current session payment ticket' in self.browser.contents)
        self.assertFalse(
          'Add previous session payment ticket' 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):
        # 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(), 'transcript.pdf')
        open(path, 'wb').write(self.browser.contents)
        print "Sample PDF matric_number_slip.pdf written to %s" % path
        return

