Index: main/waeup.uniben/trunk/src/waeup/uniben/applicants/applicant.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/applicants/applicant.py	(revision 16025)
+++ main/waeup.uniben/trunk/src/waeup/uniben/applicants/applicant.py	(revision 16078)
@@ -24,10 +24,10 @@
 from waeup.uniben.applicants.interfaces import(
     ICustomApplicant, ICustomUGApplicantEdit, ICustomPGApplicantEdit,
-    IPUTMEApplicantEdit)
+    IPUTMEApplicantEdit, ITranscriptApplicant)
 
 class CustomApplicant(NigeriaApplicant):
 
     grok.implements(ICustomApplicant, ICustomUGApplicantEdit,
-        ICustomPGApplicantEdit, IPUTMEApplicantEdit)
+        ICustomPGApplicantEdit, IPUTMEApplicantEdit, ITranscriptApplicant)
     grok.provides(ICustomApplicant)
 
Index: main/waeup.uniben/trunk/src/waeup/uniben/applicants/browser.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/applicants/browser.py	(revision 16025)
+++ main/waeup.uniben/trunk/src/waeup/uniben/applicants/browser.py	(revision 16078)
@@ -49,5 +49,6 @@
     ICustomPGApplicantEdit,
     ICustomUGApplicantEdit,
-    IPUTMEApplicantEdit)
+    IPUTMEApplicantEdit,
+    ITranscriptApplicant)
 from waeup.kofa.applicants.workflow import ADMITTED, PAID, STARTED
 from kofacustom.nigeria.applicants.interfaces import (
@@ -207,4 +208,10 @@
     @property
     def form_fields(self):
+        if self.target is not None and self.target == 'trans':
+            form_fields = grok.AutoFields(ITranscriptApplicant).omit(
+                'locked', 'suspended')
+            form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
+            form_fields['perm_address'].custom_widget = BytesDisplayWidget
+            return form_fields
         if self.target == 'ictwk':
             form_fields = grok.AutoFields(IUnibenRegistration)
@@ -372,4 +379,8 @@
     @property
     def form_fields(self):
+        if self.target is not None and self.target == 'trans':
+            form_fields = grok.AutoFields(ITranscriptApplicant)
+            form_fields['applicant_id'].for_display = True
+            return form_fields
         if self.target == 'ictwk':
             form_fields = grok.AutoFields(IUnibenRegistration)
@@ -432,4 +443,21 @@
     @property
     def form_fields(self):
+        if self.target is not None and self.target == 'trans':
+            form_fields = grok.AutoFields(ITranscriptApplicant).omit(
+                'locked', 'suspended')
+            form_fields['applicant_id'].for_display = True
+            form_fields['reg_number'].for_display = True
+            form_fields['place_of_birth'].field.required = True
+            form_fields['date_of_birth'].field.required = True
+            form_fields['nationality'].field.required = True
+            form_fields['email'].field.required = True
+            form_fields['phone'].field.required = True
+            form_fields['perm_address'].field.required = True
+            form_fields['dispatch_address'].field.required = True
+            form_fields['entry_mode'].field.required = True
+            form_fields['entry_session'].field.required = True
+            form_fields['end_session'].field.required = True
+            form_fields['course_studied'].field.required = True
+            return form_fields
         if self.target == 'ictwk':
             form_fields = grok.AutoFields(IUnibenRegistration)
Index: main/waeup.uniben/trunk/src/waeup/uniben/applicants/export.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/applicants/export.py	(revision 16025)
+++ main/waeup.uniben/trunk/src/waeup/uniben/applicants/export.py	(revision 16078)
@@ -25,5 +25,6 @@
 from kofacustom.nigeria.applicants.interfaces import (
     INigeriaUGApplicant, INigeriaPGApplicant, IBankAccount)
-from waeup.uniben.applicants.interfaces import IUnibenRegistration
+from waeup.uniben.applicants.interfaces import (
+    IUnibenRegistration, ITranscriptApplicant)
 
 class CustomApplicantExporter(NigeriaApplicantExporter):
@@ -36,4 +37,5 @@
         iface_names(IApplicantBaseData) +
         iface_names(IUnibenRegistration) +
+        iface_names(ITranscriptApplicant) +
         iface_names(IBankAccount)
         ))) + (
Index: main/waeup.uniben/trunk/src/waeup/uniben/applicants/interfaces.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/applicants/interfaces.py	(revision 16025)
+++ main/waeup.uniben/trunk/src/waeup/uniben/applicants/interfaces.py	(revision 16078)
@@ -29,4 +29,7 @@
     IApplicantBaseData,
     AppCatCertificateSource, CertificateSource)
+from waeup.kofa.university.vocabularies import StudyModeSource
+from waeup.kofa.students.vocabularies import (
+    nats_vocab, GenderSource, StudyLevelSource)
 from waeup.kofa.schoolgrades import ResultEntryField
 from waeup.kofa.interfaces import (
@@ -184,4 +187,163 @@
 #                raise Invalid(_("Matriculation number not found."))
 
+class ITranscriptApplicant(IKofaObject):
+    """A transcript applicant.
+    """
+
+    suspended = schema.Bool(
+        title = _(u'Account suspended'),
+        default = False,
+        required = False,
+        )
+
+    locked = schema.Bool(
+        title = _(u'Form locked'),
+        default = False,
+        required = False,
+        )
+
+    applicant_id = schema.TextLine(
+        title = _(u'Application Id'),
+        required = False,
+        readonly = False,
+        )
+
+    reg_number = TextLineChoice(
+        title = _(u'Kofa Registration Number'),
+        readonly = False,
+        required = True,
+        source = contextual_reg_num_source,
+        )
+
+    firstname = schema.TextLine(
+        title = _(u'First Name'),
+        required = True,
+        )
+
+    middlename = schema.TextLine(
+        title = _(u'Middle Name'),
+        required = False,
+        )
+
+    lastname = schema.TextLine(
+        title = _(u'Last Name (Surname)'),
+        required = True,
+        )
+
+    matric_number = schema.TextLine(
+        title = _(u'Matriculation Number'),
+        readonly = False,
+        required = True,
+        )
+
+    date_of_birth = FormattedDate(
+        title = _(u'Date of Birth'),
+        required = False,
+        #date_format = u'%d/%m/%Y', # Use grok-instance-wide default
+        show_year = True,
+        )
+
+    sex = schema.Choice(
+        title = _(u'Gender'),
+        source = GenderSource(),
+        required = True,
+        )
+
+    place_of_birth = schema.TextLine(
+        title = _(u'Place of Birth'),
+        readonly = False,
+        required = False,
+        )
+
+    nationality = schema.Choice(
+        vocabulary = nats_vocab,
+        title = _(u'Nationality'),
+        required = False,
+        )
+
+    email = schema.ASCIILine(
+        title = _(u'Email Address'),
+        required = True,
+        constraint=validate_email,
+        )
+
+    phone = PhoneNumber(
+        title = _(u'Phone'),
+        description = u'',
+        required = False,
+        )
+
+    perm_address = schema.Text(
+        title = _(u'Current Local Address'),
+        required = False,
+        readonly = False,
+        )
+
+    dispatch_address = schema.Text(
+        title = _(u'Dispatch Addresses'),
+        description = u'Addresses to which transcript should be posted.',
+        required = False,
+        readonly = False,
+        )
+
+    entry_mode = schema.Choice(
+        title = _(u'Entry Mode'),
+        source = StudyModeSource(),
+        required = False,
+        readonly = False,
+        )
+
+    entry_session = schema.Choice(
+        title = _(u'Entry Session'),
+        source = academic_sessions_vocab,
+        required = False,
+        readonly = False,
+        )
+
+    end_session = schema.Choice(
+        title = _(u'End Session'),
+        source = academic_sessions_vocab,
+        required = False,
+        readonly = False,
+        )
+
+    course_studied = schema.Choice(
+        title = _(u'Course of Study / Degree'),
+        source = CertificateSource(),
+        required = False,
+        readonly = False,
+        )
+
+    purpose = schema.TextLine(
+        title = _(u'Purpose of this Application'),
+        readonly = False,
+        required = False,
+        )
+
+    course_changed = schema.Choice(
+        title = _(u'Change of Study Course'),
+        description = u'If yes, select previous course of study.',
+        source = CertificateSource(),
+        readonly = False,
+        required = False,
+        )
+
+    change_level = schema.Choice(
+        title = _(u'Change Level'),
+        description = u'If yes, select level at which you changed course of study.',
+        source = StudyLevelSource(),
+        required = False,
+        readonly = False,
+        )
+
+    no_copies = schema.Choice(
+        title = _(u'Number of Copies'),
+        description = u'Must correspond with the number of dispatch addresses above.',
+        values=[1, 2, 3, 4],
+        required = False,
+        readonly = False,
+        default = 1,
+        )
+
 class ICustomUGApplicant(IApplicantBaseData, IBankAccount):
     """An undergraduate applicant.
@@ -409,5 +571,5 @@
 
 class ICustomApplicant(ICustomUGApplicant, ICustomPGApplicant,
-    IUnibenRegistration):
+    IUnibenRegistration, ITranscriptApplicant):
     """An interface for both types of applicants.
 
Index: main/waeup.uniben/trunk/src/waeup/uniben/applicants/tests/test_browser.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/applicants/tests/test_browser.py	(revision 16025)
+++ main/waeup.uniben/trunk/src/waeup/uniben/applicants/tests/test_browser.py	(revision 16078)
@@ -21,8 +21,12 @@
 """
 import os
+import datetime
+import pytz
 from StringIO import StringIO
-from datetime import datetime
 from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
 from zope.securitypolicy.interfaces import IPrincipalRoleManager
+from zope.component import createObject, getUtility
+from waeup.kofa.configuration import SessionConfiguration
+from waeup.kofa.interfaces import IUserAccount
 from waeup.kofa.browser.tests.test_pdf import samples_dir
 from waeup.kofa.applicants.container import ApplicantsContainer
@@ -31,5 +35,5 @@
 from waeup.kofa.applicants.tests.test_browser import ApplicantsFullSetup, PH_LEN
 
-session_1 = datetime.now().year - 2
+session_1 = datetime.datetime.now().year - 2
 SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
 
@@ -127,5 +131,5 @@
         self.assertTrue('<span>55</span>' in self.browser.contents)
         configuration = CustomSessionConfiguration()
-        configuration.academic_session = datetime.now().year - 2
+        configuration.academic_session = datetime.datetime.now().year - 2
         self.app['configuration'].addSessionConfiguration(configuration)
         # Admission checking fee is 0, thus admission checking payment
@@ -290,2 +294,61 @@
         open(path, 'wb').write(self.browser.contents)
         print "Sample ictwk_application_slip.pdf written to %s" % path
+
+    def test_transcript_payment(self):
+        configuration = SessionConfiguration()
+        configuration.academic_session = session_1
+        self.app['configuration'].addSessionConfiguration(configuration)
+        # Add special application container
+        applicantscontainer = ApplicantsContainer()
+        applicantscontainer.year = session_1
+        applicantscontainer.application_fee = 200.0
+        applicantscontainer.code = u'trans1234'
+        applicantscontainer.prefix = 'trans'
+        applicantscontainer.title = u'This is a trans container'
+        applicantscontainer.application_category = 'no'
+        applicantscontainer.mode = 'create'
+        applicantscontainer.strict_deadline = True
+        applicantscontainer.with_picture = False
+        delta = datetime.timedelta(days=10)
+        applicantscontainer.startdate = datetime.datetime.now(pytz.utc) - delta
+        applicantscontainer.enddate = datetime.datetime.now(pytz.utc) + delta
+        self.app['applicants']['trans1234'] = applicantscontainer
+        # Add an applicant
+        applicant = createObject('waeup.Applicant')
+        # reg_number is the only field which has to be preset here
+        # because managers are allowed to edit this required field
+        applicant.reg_number = u'12345'
+        self.app['applicants']['trans1234'].addApplicant(applicant)
+        IUserAccount(
+            self.app['applicants']['trans1234'][
+            applicant.application_number]).setPassword('apwd')
+        # Login
+        self.browser.open(self.login_path)
+        self.browser.getControl(
+            name="form.login").value = applicant.applicant_id
+        self.browser.getControl(name="form.password").value = 'apwd'
+        self.browser.getControl("Login").click()
+        self.browser.getLink("Application record").click()
+        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
+        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
+        self.browser.getControl(name="form.nationality").value = ['NG']
+        self.browser.getControl(name="form.firstname").value = 'Angela'
+        self.browser.getControl(name="form.lastname").value = 'Merkel'
+        self.browser.getControl(name="form.sex").value = ['f']
+        self.browser.getControl(name="form.no_copies").value = ['3']
+        self.browser.getControl(name="form.course_studied").value = ['CERT1']
+        self.browser.getControl(name="form.matric_number").value = '234'
+        self.browser.getControl(name="form.place_of_birth").value = 'Bochum'
+        self.browser.getControl(name="form.dispatch_address").value = 'Kuensche'
+        self.browser.getControl(name="form.perm_address").value = 'Kuensche'
+        self.browser.getControl(name="form.entry_mode").value = ['ug_ft']
+        self.browser.getControl(name="form.entry_session").value = ['2014']
+        self.browser.getControl(name="form.end_session").value = ['2015']
+        self.browser.getControl(name="form.phone.country").value = ['+234']
+        self.browser.getControl(name="form.phone.ext").value = '5678'
+        self.browser.getControl("Save").click()
+        self.browser.getControl("Add online payment ticket").click()
+        self.assertTrue('Payment ticket created' in self.browser.contents)
+        self.assertTrue('<span>200.0</span>' in self.browser.contents)
+        self.assertEqual(applicant.values()[0].amount_auth, 200.0)
+        return
Index: main/waeup.uniben/trunk/src/waeup/uniben/applicants/utils.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/applicants/utils.py	(revision 16025)
+++ main/waeup.uniben/trunk/src/waeup/uniben/applicants/utils.py	(revision 16078)
@@ -60,4 +60,5 @@
                  '(2nd supplementary advert)', 'ASE'],
         'spft': ['Special Full-Time Programmes', 'SP'],
+        'trans': ['Transcript Application', 'TR'],
         }
 
