Index: main/waeup.fceokene/trunk/src/waeup/fceokene/applicants/applicant.py
===================================================================
--- main/waeup.fceokene/trunk/src/waeup/fceokene/applicants/applicant.py	(revision 9062)
+++ main/waeup.fceokene/trunk/src/waeup/fceokene/applicants/applicant.py	(revision 9063)
@@ -19,10 +19,11 @@
 import grok
 from zope.interface import implementedBy
-from waeup.kofa.applicants.applicant import Applicant, ApplicantFactory
+from waeup.kofa.applicants.applicant import ApplicantFactory
 from waeup.kofa.utils.helpers import attrs_to_fields
+from kofacustom.nigeria.applicants.applicant import NigeriaApplicant
 from waeup.fceokene.applicants.interfaces import(
     ICustomApplicant, ICustomUGApplicantEdit, ICustomPGApplicantEdit, IPUTMEApplicantEdit)
 
-class CustomApplicant(Applicant):
+class CustomApplicant(NigeriaApplicant):
 
     grok.implements(ICustomApplicant, ICustomUGApplicantEdit,
@@ -30,8 +31,5 @@
     grok.provides(ICustomApplicant)
 
-    create_names = Applicant.create_names + [
-        'lga', 'nationality', 'perm_address']
-
-# Set all attributes of Applicant required in IApplicant as field
+# Set all attributes of CustomApplicant required in ICustomApplicant as field
 # properties. Doing this, we do not have to set initial attributes
 # ourselves and as a bonus we get free validation when an attribute is
Index: main/waeup.fceokene/trunk/src/waeup/fceokene/applicants/export.py
===================================================================
--- main/waeup.fceokene/trunk/src/waeup/fceokene/applicants/export.py	(revision 9062)
+++ 	(revision )
@@ -1,38 +1,0 @@
-## $Id$
-##
-## Copyright (C) 2012 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
-##
-"""Exporters for applicant-related stuff.
-"""
-import grok
-from waeup.kofa.applicants.interfaces import IApplicantBaseData
-from waeup.kofa.applicants.export import ApplicantsExporter
-from kofacustom.nigeria.applicants.interfaces import (
-    INigeriaUGApplicant, INigeriaPGApplicant)
-from waeup.fceokene.applicants.interfaces import (
-    ICustomUGApplicant, ICustomPGApplicant)
-
-class CustomApplicantsExporter(ApplicantsExporter):
-    """Exporter for Custom Applicants.
-    """
-
-    fields = tuple(sorted(set(
-        ICustomUGApplicant.names() +
-        ICustomPGApplicant.names() +
-        INigeriaUGApplicant.names() +
-        INigeriaPGApplicant.names() +
-        IApplicantBaseData.names()
-        ))) + ('container_code',)
Index: main/waeup.fceokene/trunk/src/waeup/fceokene/applicants/tests/test_browser.py
===================================================================
--- main/waeup.fceokene/trunk/src/waeup/fceokene/applicants/tests/test_browser.py	(revision 9062)
+++ 	(revision )
@@ -1,402 +1,0 @@
-## $Id$
-##
-## 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.schema.interfaces import ConstraintNotSatisfied
-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 two different applicants containers
-        self.pgcontainer = ApplicantsContainer()
-        self.pgcontainer.code = u'pgft2011'
-        self.pgcontainer.prefix = u'pgft'
-        self.pgcontainer.application_category = u'pg_ft'
-        self.pgcontainer.year = 2011
-        self.pgcontainer.application_fee = 300.0
-        self.pgcontainer.title = u'This is the pgft2011 container'
-        self.app['applicants']['pgft2011'] = self.pgcontainer
-        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)
-        self.certificate2 = createObject('waeup.Certificate')
-        self.certificate2.code = 'CERT2'
-        self.certificate2.application_category = 'pg_ft'
-        self.certificate2.start_level = 100
-        self.certificate2.end_level = 500
-        self.certificate.study_mode = u'pg_ft'
-        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
-            self.certificate2)
-
-        # Add (customized) applicants
-        pgapplicant = createObject(u'waeup.Applicant')
-        pgapplicant.firstname = u'Anna'
-        pgapplicant.lastname = u'Post'
-        self.app['applicants']['pgft2011'].addApplicant(pgapplicant)
-        self.pgapplication_number = pgapplicant.application_number
-        self.pgapplicant = self.app['applicants']['pgft2011'][
-            self.pgapplication_number]
-
-        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.pgapplicant_path = ('http://localhost/app/applicants/pgft2011/%s'
-            % self.pgapplication_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_manage_and_view_applicant(self):
-        # Managers can manage pg applicants.
-        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-        # The IPGApplicant interface is really used in all pages.
-        self.browser.open(self.pgapplicant_path)
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        self.assertTrue('Employer' in self.browser.contents)
-        self.browser.open(self.pgapplicant_path + '/manage')
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        self.assertTrue('Employer' in self.browser.contents)
-        self.browser.open(self.pgapplicant_path + '/edit')
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        self.assertTrue('Employer' in self.browser.contents)
-        self.browser.open(self.pgapplicant_path + '/application_slip.pdf')
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        # If we view the applicant in the ug container,
-        # the employer field doesn't appear.
-        self.browser.open(self.ugapplicant_path)
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        self.assertFalse('Employer' in self.browser.contents)
-        self.browser.open(self.ugapplicant_path + '/manage')
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        # We can save the applicant.
-        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.assertFalse('Employer' in self.browser.contents)
-        self.browser.open(self.ugapplicant_path + '/edit')
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        self.assertFalse('Employer' in self.browser.contents)
-        self.browser.open(self.ugapplicant_path + '/application_slip.pdf')
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        return
-
-    def test_set_wrong_course1(self):
-        self.ugapplicant.course1 = self.certificate
-        self.assertRaises(
-            ConstraintNotSatisfied,
-            setattr, self.ugapplicant, 'course1', self.certificate2)
-        self.pgapplicant.course1 = self.certificate2
-        self.assertRaises(
-            ConstraintNotSatisfied,
-            setattr, self.pgapplicant, 'course1', self.certificate)
-        return
-
-    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)
-
-        # PG applicants pay more
-        self.browser.open(self.pgapplicant_path)
-        self.browser.open(self.pgapplicant_path + '/manage')
-        self.assertEqual(self.browser.headers['Status'], '200 Ok')
-        self.fill_correct_values()
-        self.browser.getControl(name="form.course1").value = ['CERT2']
-        self.browser.getControl(name="form.reg_number").value = '2345'
-        self.browser.getControl(name="form.firstname").value = 'Anna'
-        self.browser.getControl("Save").click()
-        self.assertMatches('...Form has been saved...', self.browser.contents)
-        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.pgapplicant.keys()[0]
-        payment = self.pgapplicant[payment_id]
-        self.assertEqual(payment.p_item,'This is the pgft2011 container')
-        self.assertEqual(payment.p_session,2011)
-        self.assertEqual(payment.p_category,'application')
-        self.assertEqual(payment.amount_auth, 300.0)
-        return
-
-    def test_register_applicant_update(self):
-        # An applicant can register himself.
-        self.ugapplicant.reg_number = u'1234'
-        notify(grok.ObjectModifiedEvent(self.ugapplicant))
-        self.browser.open('http://localhost/app/applicants/app2011/')
-        self.browser.getLink("Register for application").click()
-        # Fill the edit form with suitable values
-        self.browser.getControl(name="form.firstname").value = 'Klaus'
-        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
-        self.browser.getControl(name="form.reg_number").value = '1234'
-        self.browser.getControl("Get login credentials").click()
-        self.assertMatches('...Your registration was successful...',
-            self.browser.contents)
-        self.assertFalse('...<td>Password:</td>...' in self.browser.contents)
-        # The new applicant can be found in the catalog via the email address
-        cat = getUtility(ICatalog, name='applicants_catalog')
-        results = list(
-            cat.searchResults(email=('xx@yy.zz', 'xx@yy.zz')))
-        applicant = results[0]
-        self.assertEqual(applicant.lastname,'Under')
-        # The applicant can be found in the catalog via the reg_number
-        results = list(
-            cat.searchResults(
-            reg_number=(applicant.reg_number, applicant.reg_number)))
-        self.assertEqual(applicant,results[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(
-            'aggregate,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,result_uploaded,screening_date,screening_score,screening_venue,sex,'
-            'state,student_id,suspended,'
-            '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,,0,dp2011'
-            in result)
-        # We can import the same file 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,
-            ['aggreagate','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','result_uploaded',
-            'screening_date','screening_score','screening_venue','sex',
-            'state','student_id','suspended','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,
-            ['aggregate','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','result_uploaded','screening_date','screening_score',
-            'screening_venue','sex',
-            'state','student_id','suspended','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
