Index: main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/browser.py
===================================================================
--- main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/browser.py	(revision 15000)
+++ main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/browser.py	(revision 15087)
@@ -19,10 +19,120 @@
 """
 import grok
+from zope.formlib.textwidgets import BytesDisplayWidget
 from waeup.kofa.applicants.browser import (
     ApplicantRegistrationPage, ApplicantsContainerPage)
 from kofacustom.nigeria.applicants.browser import (
     NigeriaApplicantDisplayFormPage,
-    NigeriaPDFApplicationSlip)
+    NigeriaPDFApplicationSlip,
+    NigeriaApplicantManageFormPage,
+    NigeriaApplicantEditFormPage)
+from kofacustom.nigeria.applicants.interfaces import (
+    UG_OMIT_DISPLAY_FIELDS,
+    UG_OMIT_PDF_FIELDS,
+    UG_OMIT_MANAGE_FIELDS,
+    UG_OMIT_EDIT_FIELDS,
+    PG_OMIT_DISPLAY_FIELDS,
+    PG_OMIT_PDF_FIELDS,
+    PG_OMIT_MANAGE_FIELDS,
+    PG_OMIT_EDIT_FIELDS,
+    )
+from kofacustom.edopoly.applicants.interfaces import (
+    ICustomUGApplicantEdit, ICustomUGApplicant,
+    ICustomPGApplicantEdit, ICustomPGApplicant)
 
 from kofacustom.edopoly.interfaces import MessageFactory as _
 
+# Fields to be omitted in all display forms. course_admitted is
+# rendered separately.
+
+OMIT_DISPLAY_FIELDS = ('locked', 'course_admitted',
+    'result_uploaded', 'suspended', 'special_application',
+    'bank_account_number',
+    'bank_account_name',
+    'bank_name')
+
+# UG students are all undergraduate students.
+UG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
+    'jamb_subjects_list', 'programme_type')
+UG_OMIT_PDF_FIELDS = UG_OMIT_DISPLAY_FIELDS + ('phone',)
+UG_OMIT_MANAGE_FIELDS = (
+    'special_application',
+    'jamb_subjects_list',
+    'programme_type')
+UG_OMIT_EDIT_FIELDS = UG_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
+    'student_id',
+    'notice',
+    'screening_score',
+    'screening_venue',
+    'screening_date',
+#    'jamb_age',
+#    'jamb_subjects',
+#    'jamb_score',
+#    'jamb_reg_number',
+    'aggregate')
+
+class CustomApplicantDisplayFormPage(NigeriaApplicantDisplayFormPage):
+    """A display view for applicant data.
+    """
+
+    @property
+    def form_fields(self):
+        target = getattr(self.context.__parent__, 'prefix', None)
+        form_fields = grok.AutoFields(ICustomUGApplicant)
+        form_fields['notice'].custom_widget = BytesDisplayWidget
+        form_fields['jamb_subjects'].custom_widget = BytesDisplayWidget
+        if not getattr(self.context, 'student_id'):
+            form_fields = form_fields.omit('student_id')
+        if not getattr(self.context, 'screening_score'):
+            form_fields = form_fields.omit('screening_score')
+        if not getattr(self.context, 'screening_venue'):
+            form_fields = form_fields.omit('screening_venue')
+        if not getattr(self.context, 'screening_date'):
+            form_fields = form_fields.omit('screening_date')
+        return form_fields
+
+class CustomPDFApplicationSlip(NigeriaPDFApplicationSlip):
+
+    @property
+    def form_fields(self):
+        target = getattr(self.context.__parent__, 'prefix', None)
+        form_fields = grok.AutoFields(ICustomUGApplicant)
+        for field in UG_OMIT_PDF_FIELDS:
+            form_fields = form_fields.omit(field)
+        if not getattr(self.context, 'student_id'):
+            form_fields = form_fields.omit('student_id')
+        if not getattr(self.context, 'screening_score'):
+            form_fields = form_fields.omit('screening_score')
+        if not getattr(self.context, 'screening_venue'):
+            form_fields = form_fields.omit('screening_venue')
+        if not getattr(self.context, 'screening_date'):
+            form_fields = form_fields.omit('screening_date')
+        return form_fields
+
+class CustomApplicantManageFormPage(NigeriaApplicantManageFormPage):
+    """A full edit view for applicant data.
+    """
+
+    @property
+    def form_fields(self):
+        target = getattr(self.context.__parent__, 'prefix', None)
+        form_fields = grok.AutoFields(ICustomUGApplicant)
+        for field in UG_OMIT_MANAGE_FIELDS:
+            form_fields = form_fields.omit(field)
+        form_fields['student_id'].for_display = True
+        form_fields['applicant_id'].for_display = True
+        return form_fields
+
+class CustomApplicantEditFormPage(NigeriaApplicantEditFormPage):
+    """An applicant-centered edit view for applicant data.
+    """
+
+    @property
+    def form_fields(self):
+        target = getattr(self.context.__parent__, 'prefix', None)
+        form_fields = grok.AutoFields(ICustomUGApplicantEdit)
+        for field in UG_OMIT_EDIT_FIELDS:
+            form_fields = form_fields.omit(field)
+        form_fields['applicant_id'].for_display = True
+        form_fields['reg_number'].for_display = True
+        return form_fields
Index: main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/interfaces.py
===================================================================
--- main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/interfaces.py	(revision 15000)
+++ main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/interfaces.py	(revision 15087)
@@ -45,6 +45,175 @@
     This interface defines the least common multiple of all fields
     in ug application forms. In customized forms, fields can be excluded by
-    adding them to the UG_OMIT* tuples.
-    """
+    adding them to the OMIT* tuples.
+    """
+
+    nationality = schema.Choice(
+        source = nats_vocab,
+        title = _(u'Nationality'),
+        required = True,
+        )
+    lga = schema.Choice(
+        source = LGASource(),
+        title = _(u'State/LGA (Nigerians only)'),
+        required = False,
+        )
+    #perm_address = schema.Text(
+    #    title = _(u'Permanent Address'),
+    #    required = False,
+    #    )
+    course1 = schema.Choice(
+        title = _(u'1st Choice Course of Study'),
+        source = AppCatCertificateSource(),
+        required = False,
+        )
+    course2 = schema.Choice(
+        title = _(u'2nd Choice Course of Study'),
+        source = AppCatCertificateSource(),
+        required = False,
+        )
+    olevel_type = schema.Choice(
+        title = _(u'1st Qualification Obtained'),
+        required = False,
+        readonly = False,
+        vocabulary = exam_types,
+        )
+    olevel_school = schema.TextLine(
+        title = _(u'1st Institution Attended'),
+        required = False,
+        readonly = False,
+        )
+    olevel_exam_number = schema.TextLine(
+        title = _(u'1st Exam Number'),
+        required = False,
+        readonly = False,
+        )
+    olevel_exam_date = FormattedDate(
+        title = _(u'1st Exam Date'),
+        required = False,
+        readonly = False,
+        show_year = True,
+        )
+    olevel_results = schema.List(
+        title = _(u'1st Exam Results'),
+        value_type = ResultEntryField(),
+        required = False,
+        readonly = False,
+        defaultFactory=list,
+        )
+    olevel_type2 = schema.Choice(
+        title = _(u'2nd Qualification Obtained'),
+        required = False,
+        readonly = False,
+        vocabulary = exam_types,
+        )
+    olevel_school2 = schema.TextLine(
+        title = _(u'2nd Institution Attended'),
+        required = False,
+        readonly = False,
+        )
+    olevel_exam_number2 = schema.TextLine(
+        title = _(u'2nd Exam Number'),
+        required = False,
+        readonly = False,
+        )
+    olevel_exam_date2 = FormattedDate(
+        title = _(u'2nd Exam Date'),
+        required = False,
+        readonly = False,
+        show_year = True,
+        )
+    olevel_results2 = schema.List(
+        title = _(u'2nd Exam Results'),
+        value_type = ResultEntryField(),
+        required = False,
+        readonly = False,
+        defaultFactory=list,
+        )
+    hq_type = schema.Choice(
+        title = _(u'Qualification Obtained'),
+        required = False,
+        readonly = False,
+        vocabulary = high_qual,
+        )
+    hq_matric_no = schema.TextLine(
+        title = _(u'Former Matric Number'),
+        required = False,
+        readonly = False,
+        )
+    hq_degree = schema.Choice(
+        title = _(u'Class of Degree'),
+        required = False,
+        readonly = False,
+        vocabulary = high_grade,
+        )
+    hq_school = schema.TextLine(
+        title = _(u'Institution Attended'),
+        required = False,
+        readonly = False,
+        )
+    hq_session = schema.TextLine(
+        title = _(u'Years Attended'),
+        required = False,
+        readonly = False,
+        )
+    hq_disc = schema.TextLine(
+        title = _(u'Discipline'),
+        required = False,
+        readonly = False,
+        )
+    jamb_subjects = schema.Text(
+        title = _(u'Subjects and Scores'),
+        description = _(u'(one subject with score per line)'),
+        required = False,
+        )
+    jamb_score = schema.Int(
+        title = _(u'Total JAMB Score'),
+        required = False,
+        )
+    jamb_reg_number = schema.TextLine(
+        title = _(u'JAMB Registration Number'),
+        required = False,
+        )
+    notice = schema.Text(
+        title = _(u'Notice'),
+        required = False,
+        )
+    screening_venue = schema.TextLine(
+        title = _(u'Screening Venue'),
+        required = False,
+        )
+    screening_date = schema.TextLine(
+        title = _(u'Screening Date'),
+        required = False,
+        )
+    screening_score = schema.Int(
+        title = _(u'Screening Score (%)'),
+        required = False,
+        )
+    aggregate = schema.Int(
+        title = _(u'Aggregate Score (%)'),
+        description = _(u'(average of relative JAMB and PUTME scores)'),
+        required = False,
+        )
+    result_uploaded = schema.Bool(
+        title = _(u'Result uploaded'),
+        default = False,
+        required = False,
+        )
+    student_id = schema.TextLine(
+        title = _(u'Student Id'),
+        required = False,
+        readonly = False,
+        )
+    course_admitted = schema.Choice(
+        title = _(u'Admitted Course of Study'),
+        source = CertificateSource(),
+        required = False,
+        )
+    locked = schema.Bool(
+        title = _(u'Form locked'),
+        default = False,
+        required = False,
+        )
 
 class ICustomPGApplicant(INigeriaPGApplicant):
@@ -76,5 +245,5 @@
         """
 
-class ICustomUGApplicantEdit(INigeriaUGApplicantEdit):
+class ICustomUGApplicantEdit(ICustomUGApplicant):
     """An undergraduate applicant interface for edit forms.
 
@@ -88,5 +257,35 @@
     """
 
-class ICustomPGApplicantEdit(INigeriaPGApplicantEdit):
+
+    email = schema.ASCIILine(
+        title = _(u'Email Address'),
+        required = True,
+        constraint=validate_email,
+        )
+    date_of_birth = FormattedDate(
+        title = _(u'Date of Birth'),
+        required = True,
+        show_year = True,
+        )
+    jamb_reg_number = schema.TextLine(
+        title = _(u'JAMB Registration Number'),
+        required = True,
+        )
+    course1 = schema.Choice(
+        title = _(u'1st Choice Course of Study'),
+        source = AppCatCertificateSource(),
+        required = True,
+        )
+
+ICustomUGApplicantEdit[
+    'date_of_birth'].order =  ICustomUGApplicant['date_of_birth'].order
+ICustomUGApplicantEdit[
+    'email'].order =  ICustomUGApplicant['email'].order
+ICustomUGApplicantEdit[
+    'jamb_reg_number'].order =  ICustomUGApplicant['jamb_reg_number'].order
+ICustomUGApplicantEdit[
+    'course1'].order =  ICustomUGApplicant['course1'].order
+
+class ICustomPGApplicantEdit(ICustomPGApplicant):
     """A postgraduate applicant interface for editing.
 
Index: main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/utils.py
===================================================================
--- main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/utils.py	(revision 15000)
+++ main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/utils.py	(revision 15087)
@@ -29,2 +29,34 @@
     """A collection of parameters and methods subject to customization.
     """
+
+    APP_TYPES_DICT = {
+        #'pude': ['Post-UDE Screening', 'PUDE'],
+        #'prence': ['Pre-NCE Programme', 'PRE'],
+        #'sandwich': ['Part-Time Degree in Education', 'SAND'],
+        'pt': ['Part-Time Degree Programmes', 'PTP'],
+        #'putme': ['Post-UTME Screening Exercise', 'PUTME'],
+        'app': ['General Studies', 'APP'],
+        #'cest': ['Common Entry Screening Test', 'CEST'],
+        #'ct': ['Certificate Programmes', 'CTP'],
+        #'dp': ['Diploma Programmes', 'DPP'],
+        #'pce': ['PCE Screening', 'PCE'],
+        #'pgft': ['Postgraduate Full-Time Programmes', 'PG'],
+        #'pgpt': ['Postgraduate Part-Time Programmes', 'PG'],
+        #'pre': ['Pre-Degree Studies', 'PRE'],
+        #'cbt': ['CBT Practice Test', 'CBT'],
+        'ase': ['Admission Screening Exercise', 'ASE'], # successor of putme
+        }
+
+    SEPARATORS_DICT = {
+        'form.applicant_id': _(u'Base Data'),
+        'form.course1': _(u'Programmes/Courses Desired'),
+        'form.hq_type': _(u'Higher Education Record'),
+        'form.presently': _(u'Course or Programme Presently Attending'),
+        'form.nysc_year': _(u'NYSC Information'),
+        'form.employer': _(u'Employment History'),
+        'form.jamb_subjects': _(u'JAMB Data'),
+        'form.notice': _(u'Application Process Information'),
+        'form.pp_school': _(u'Post Primary School Qualification'),
+        'form.presently_inst': _(u'Presently attending a course or programme'),
+        'form.olevel_type': _(u"'O' Level Records"),
+        }
