## $Id: tests.py 8671 2012-06-11 07:09:06Z 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 datetime
import grok
import pytz
from zope.event import notify
from zope.intid.interfaces import IIntIds
from zope.interface.verify import verifyClass, verifyObject
from zope.component.hooks import setSite, clearSite
from zope.component import createObject, getUtility
from zope.catalog.interfaces import ICatalog
from zope.testbrowser.testing import Browser
from hurry.workflow.interfaces import IWorkflowState
from waeup.kofa.app import University
from waeup.kofa.university.faculty import Faculty
from waeup.kofa.university.department import Department
from waeup.kofa.testing import FunctionalTestCase
from waeup.kofa.configuration import SessionConfiguration
from waeup.kofa.applicants.container import ApplicantsContainer
from waeup.kofa.applicants.tests.test_batching import ApplicantImportExportSetup
from waeup.kofa.interfaces import IBatchProcessor
from waeup.fceokene.testing import FunctionalLayer
from waeup.fceokene.applicants.export import CustomApplicantsExporter
from waeup.fceokene.applicants.batching import CustomApplicantProcessor


class ApplicantUITest(FunctionalTestCase):
    """Perform some browser tests.
    """
    layer = FunctionalLayer

    def setUp(self):
        super(ApplicantUITest, 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)

        # Add an applicants containers
        self.ugcontainer = ApplicantsContainer()
        self.ugcontainer.code = u'putme2011'
        self.ugcontainer.prefix = u'putme'
        self.ugcontainer.application_category = u'basic'
        self.ugcontainer.year = 2011
        self.ugcontainer.application_fee = 200.0
        self.ugcontainer.title = u'This is the app2011 container'
        self.app['applicants']['app2011'] = self.ugcontainer

        self.ugcontainer.mode = 'update'
        delta = datetime.timedelta(days=10)
        self.ugcontainer.startdate = datetime.datetime.now(pytz.utc) - delta
        self.ugcontainer.enddate = datetime.datetime.now(pytz.utc) + delta

        # Populate university
        self.certificate = createObject('waeup.Certificate')
        self.certificate.code = 'CERT1'
        self.certificate.application_category = 'basic'
        self.certificate.start_level = 100
        self.certificate.end_level = 500
        self.certificate.study_mode = u'ug_ft'
        self.app['faculties']['fac1'] = Faculty()
        self.app['faculties']['fac1']['dep1'] = Department()
        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
            self.certificate)

        # Add (customized) applicant
        ugapplicant = createObject(u'waeup.Applicant')
        ugapplicant.firstname = u'Klaus'
        ugapplicant.lastname = u'Under'
        self.app['applicants']['app2011'].addApplicant(ugapplicant)
        self.ugapplication_number = ugapplicant.application_number
        self.ugapplicant = self.app['applicants']['app2011'][
            self.ugapplication_number]
        self.ugapplicant_path = ('http://localhost/app/applicants/app2011/%s'
            % self.ugapplication_number)

        self.browser = Browser()
        self.browser.handleErrors = False

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

    def fill_correct_values(self):
        self.browser.getControl(name="form.reg_number").value = '1234'
        self.browser.getControl(name="form.firstname").value = 'John'
        self.browser.getControl(name="form.lastname").value = 'Tester'
        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
        self.browser.getControl(name="form.lga").value = ['foreigner']
        self.browser.getControl(name="form.nationality").value = ['NG']
        self.browser.getControl(name="form.sex").value = ['m']
        self.browser.getControl(name="form.email").value = 'xx@yy.zz'

    def test_application_payment(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')

        # UG (UTME) applicant
        self.browser.open(self.ugapplicant_path)
        self.browser.open(self.ugapplicant_path + '/manage')
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        self.fill_correct_values()
        self.browser.getControl(name="form.course1").value = ['CERT1']
        self.browser.getControl("Save").click()
        self.assertMatches('...Form has been saved...', self.browser.contents)
        self.browser.getControl("Save").click()
        self.browser.getControl("Add online payment ticket").click()
        self.assertMatches('...Payment ticket created...',
                           self.browser.contents)
        self.assertMatches('...Amount Authorized...',
                           self.browser.contents)
        payment_id = self.ugapplicant.keys()[0]
        payment = self.ugapplicant[payment_id]
        self.assertEqual(payment.p_item,'This is the app2011 container')
        self.assertEqual(payment.p_session,2011)
        self.assertEqual(payment.p_category,'application')
        self.assertEqual(payment.amount_auth, 200.0)

        return

    def test_create_ugstudent(self):
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        manage_path = 'http://localhost/app/applicants/%s/%s/%s' % (
            'app2011', self.ugapplicant.application_number, 'manage')
        self.browser.open(manage_path)
        self.fill_correct_values()
        self.browser.getControl("Save").click()
        IWorkflowState(self.ugapplicant).setState('admitted')
        self.browser.getControl(name="form.course1").value = ['CERT1']
        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
        self.browser.getControl("Save").click()
        self.browser.getLink("Create student").click()
        student_id =  self.app['students'].keys()[0]
        self.assertTrue(('Student %s created' % student_id)
            in self.browser.contents)
        student = self.app['students'][student_id]
        self.assertEqual(student.email, 'xx@yy.zz')
        self.assertEqual(student.firstname, 'John')
        self.assertEqual(student.lastname, 'Tester')
        # Also additional attributes have been copied.
        self.assertEqual(student.lga, 'foreigner')
        self.assertEqual(student.nationality, 'NG')
        return

class ApplicantsExporterTest(ApplicantImportExportSetup):

    layer = FunctionalLayer

    def setUp(self):
        super(ApplicantsExporterTest, self).setUp()
        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
        self.cat = getUtility(ICatalog, name='applicants_catalog')
        self.intids = getUtility(IIntIds)
        return

    def setup_applicant(self, applicant):
        # set predictable values for `applicant`
        applicant.reg_number = u'123456'
        applicant.applicant_id = u'dp2011_654321'
        applicant.firstname = u'Anna'
        applicant.lastname = u'Tester'
        applicant.middlename = u'M.'
        applicant.date_of_birth = datetime.date(1981, 2, 4)
        applicant.sex = 'f'
        applicant.email = 'anna@sample.com'
        applicant.phone = u'+234-123-12345'
        applicant.course1 = self.certificate
        applicant.course2 = self.certificate
        applicant.course_admitted = self.certificate
        applicant.notice = u'Some notice\nin lines.'
        applicant.screening_score = 98
        applicant.screening_venue = u'Exam Room'
        applicant.screening_date = u'Saturday, 16th June 2012 2:00:00 PM'
        applicant.password = 'any password'
        return applicant

    def test_export_reimport_all(self):
        # we can export all applicants in a portal
        # set values we can expect in export file
        self.applicant = self.setup_applicant(self.applicant)
        exporter = CustomApplicantsExporter()
        exporter.export_all(self.app, self.outfile)
        result = open(self.outfile, 'rb').read()
        # The exported records do contain a real date in their
        # history dict. We skip the date and split the comparison
        # into two parts.
        self.assertTrue(
            'applicant_id,application_date,application_number,course1,course2,'
            'course_admitted,date_of_birth,display_fullname,email,emp2_end,'
            'emp2_position,emp2_reason,emp2_start,emp_end,emp_position,'
            'emp_reason,emp_start,employer,employer2,firstname,history,'
            'hq_degree,hq_disc,hq_matric_no,hq_school,hq_session,hq_type,'
            'jamb_score,jamb_subjects,lastname,lga,locked,middlename,'
            'nationality,notice,nysc_lga,'
            'nysc_year,password,perm_address,phone,pp_school,presently_inst,'
            'reg_number,screening_date,screening_score,screening_venue,sex,'
            'state,student_id,'
            'container_code'
            in result)
        self.assertTrue(
            'Application initialized by system\'],,,,,,,,,Tester,,0,M.,,'
            '"Some notice\nin lines.",,,any password,,+234-123-12345,,,'
            '123456,"Saturday, 16th June 2012 2:00:00 PM",98,Exam Room,f,'
            'initialized,,dp2011' in result)
        # We can import the same file with if we ignore some columns.
        # Since the applicants_catalog hasn't been notified, the same
        # record with same reg_number can be imported twice.
        processor = CustomApplicantProcessor()
        result = processor.doImport(
            self.outfile,
            ['ignore_applicant_id','application_date','ignore_application_number',
            'course1','course2',
            'course_admitted','date_of_birth','ignore3','email','emp2_end',
            'emp2_position','emp2_reason','emp2_start','emp_end','emp_position',
            'emp_reason','emp_start','employer','employer2','firstname','ignore4',
            'hq_degree','hq_disc','hq_matric_no','hq_school','hq_session','hq_type',
            'jamb_score','jamb_subjects','lastname','lga','locked','middlename',
            'nationality','notice','nysc_lga',
            'nysc_year','password','perm_address','phone','pp_school','presently_inst',
            'reg_number','screening_date','screening_score','screening_venue','sex',
            'state','student_id','container_code'],
            mode='create')
        num_succ, num_fail, finished_path, failed_path = result
        self.assertEqual(num_succ,1)
        self.assertEqual(num_fail,0)
        # Now we ignore also the container_code and import the same file 
        # in update mode which means that ICustomApplicantUpdateByRegNo 
        # is used for field conversion. applicant_id must be ignored
        # too since the previous import has notified the applicants_catalog
        # so that the portal 'knows' that reg_number is in use.
        processor = CustomApplicantProcessor()
        result = processor.doImport(
            self.outfile,
            ['ignore_applicant_id','application_date','ignore_application_number',
            'course1','course2',
            'course_admitted','date_of_birth','ignore3','email','emp2_end',
            'emp2_position','emp2_reason','emp2_start','emp_end','emp_position',
            'emp_reason','emp_start','employer','employer2','firstname','ignore4',
            'hq_degree','hq_disc','hq_matric_no','hq_school','hq_session','hq_type',
            'jamb_score','jamb_subjects','lastname','lga','locked','middlename',
            'nationality','notice','nysc_lga',
            'nysc_year','password','perm_address','phone','pp_school','presently_inst',
            'reg_number','screening_date','screening_score','screening_venue','sex',
            'state','student_id','ignore_container_code'],
            mode='update')
        num_succ, num_fail, finished_path, failed_path = result
        self.assertEqual(num_succ,1)
        self.assertEqual(num_fail,0)
        return
