source: main/waeup.aaue/trunk/src/waeup/aaue/applicants/browser.py @ 15867

Last change on this file since 15867 was 15841, checked in by Henrik Bettermann, 5 years ago

Fix links.

Change fac_dep category title.

  • Property svn:keywords set to Id
File size: 30.6 KB
RevLine 
[10298]1## $Id: browser.py 15841 2019-11-22 12:43:00Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""UI components for basic applicants and related components.
19"""
20import grok
21import os
[13996]22from zope.component import getUtility, getAdapter
23from zope.i18n import translate
[14027]24from hurry.workflow.interfaces import IWorkflowState
[10298]25from waeup.kofa.interfaces import (
[13996]26    IExtFileStore, IFileStoreNameChooser, IKofaUtils)
[10298]27from zope.formlib.textwidgets import BytesDisplayWidget
28from waeup.kofa.utils.helpers import string_from_bytes, file_size
[13996]29from waeup.kofa.applicants.browser import (
30    ApplicantCheckStatusPage, ApplicantBaseDisplayFormPage)
[14027]31from waeup.kofa.applicants.workflow import STARTED, PAID
[13538]32from waeup.kofa.applicants.viewlets import PDFActionButton
[14460]33from waeup.kofa.applicants.interfaces import IApplicantRegisterUpdate
[13996]34from waeup.kofa.browser.layout import UtilityView
35from waeup.kofa.students.interfaces import IStudentsUtils
36from waeup.kofa.interfaces import IPDF
[13997]37from waeup.kofa.browser.viewlets import ManageActionButton
[10298]38from waeup.aaue.interfaces import MessageFactory as _
39from kofacustom.nigeria.applicants.browser import (
40    NigeriaApplicantDisplayFormPage,
41    NigeriaApplicantManageFormPage,
42    NigeriaApplicantEditFormPage,
43    NigeriaPDFApplicationSlip,
[10929]44    NigeriaApplicantRegistrationPage,
[11755]45    NigeriaExportPDFPaymentSlipPage,
[13545]46    )
47from kofacustom.nigeria.applicants.interfaces import OMIT_DISPLAY_FIELDS
[10298]48from waeup.aaue.applicants.interfaces import (
49    ICustomUGApplicant,
[13544]50    ICustomUGApplicantEdit,
[13996]51    ITranscriptApplicant,
[14304]52    ICertificateRequest,
[15530]53    ICustomApplicant,
[15531]54    IVerificationRequest,
55    ISendByEmailRequest
[11291]56    )
[10298]57
[13545]58UG_OMIT_FIELDS = (
59      'hq_type', 'hq_fname', 'hq_matric_no',
60      'hq_degree', 'hq_school', 'hq_session', 'hq_disc',
61      'hq_type2', 'hq_fname2', 'hq_matric_no2',
62      'hq_degree2', 'hq_school2', 'hq_session2', 'hq_disc2',
63      'hq_type3', 'hq_fname3', 'hq_matric_no3',
[13679]64      'hq_degree3', 'hq_school3', 'hq_session3', 'hq_disc3',
65      'nysc_year',
66      'nysc_location',
67      'nysc_lga',
68      'employer',
69      'emp_position',
70      'emp_start',
71      'emp_end',
72      'emp_reason',
73      'employer2',
74      'emp2_position',
75      'emp2_start',
76      'emp2_end',
77      'emp2_reason',
78      'former_matric',
[13545]79      )
[13546]80UG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
[13977]81    'jamb_subjects_list', 'master_sheet_number') + UG_OMIT_FIELDS
[13545]82UG_OMIT_PDF_FIELDS = UG_OMIT_DISPLAY_FIELDS + UG_OMIT_FIELDS + (
[14363]83      'alr_fname', 'alr_no', 'alr_date',
[13545]84      'alr_results', 'notice')
[13546]85UG_OMIT_MANAGE_FIELDS = (
86    'special_application','jamb_subjects_list',) + UG_OMIT_FIELDS
87UG_OMIT_EDIT_FIELDS = UG_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
[13545]88    'student_id',
89    'notice',
90    'jamb_age',
91    'jamb_subjects',
92    'jamb_score',
93    'jamb_reg_number',
[13679]94    'aggregate',
[13977]95    'master_sheet_number',
[13996]96    'screening_venue',
97    'screening_score',
98    'screening_date'
[13679]99    )
[10298]100
[14209]101UDE_OMIT_FIELDS = (
102      'nysc_year',
103      'nysc_location',
104      'nysc_lga',
105      'employer',
106      'emp_position',
107      'emp_start',
108      'emp_end',
109      'emp_reason',
110      'employer2',
111      'emp2_position',
112      'emp2_start',
113      'emp2_end',
114      'emp2_reason',
115      'former_matric',
116      )
117UDE_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
118    'jamb_subjects_list', 'master_sheet_number') + UDE_OMIT_FIELDS
119UDE_OMIT_PDF_FIELDS = UDE_OMIT_DISPLAY_FIELDS + UDE_OMIT_FIELDS + (
[15091]120      #'alr_fname', 'alr_no', 'alr_date', 'alr_results',
121      'hq_type2', 'hq_fname2', 'hq_matric_no2',
122      'hq_degree2', 'hq_school2', 'hq_session2', 'hq_disc2',
123      'hq_type3', 'hq_fname3', 'hq_matric_no3',
124      'hq_degree3', 'hq_school3', 'hq_session3', 'hq_disc3',
125      'notice')
[14209]126UDE_OMIT_MANAGE_FIELDS = (
127    'special_application','jamb_subjects_list',) + UDE_OMIT_FIELDS
128UDE_OMIT_EDIT_FIELDS = UDE_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
129    'student_id',
130    'notice',
131    'jamb_age',
132    'jamb_subjects',
133    'jamb_score',
134    'jamb_reg_number',
135    'aggregate',
136    'master_sheet_number',
137    'screening_venue',
138    'screening_score',
139    'screening_date'
140    )
141
[13545]142#UG_OMIT_PDF_FIELDS = tuple([
143#    element for element in UG_OMIT_PDF_FIELDS if not element == 'phone'])
[11291]144
[13545]145#UG_OMIT_PDF_FIELDS += (
146#      'reg_number','alr_fname', 'alr_no', 'alr_date',
147#      'alr_results', 'notice'
148#      )
[13538]149
[13545]150PG_OMIT_FIELDS = (
151    'fst_sit_fname',
152    'fst_sit_no',
153    'fst_sit_date',
154    'fst_sit_type',
155    'fst_sit_results',
156    'scd_sit_fname',
157    'scd_sit_no',
158    'scd_sit_date',
159    'scd_sit_type',
160    'scd_sit_results',
[13977]161    #'programme_type',
[13546]162    'jamb_age',
163    'jamb_subjects',
164    'jamb_score',
165    'jamb_reg_number',
166    'aggregate'
[13545]167    )
168PG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
169    'jamb_subjects_list',) + PG_OMIT_FIELDS
170PG_OMIT_PDF_FIELDS = PG_OMIT_DISPLAY_FIELDS + PG_OMIT_FIELDS + (
171      'reg_number','alr_fname', 'alr_no', 'alr_date',
[13679]172      'alr_results', 'notice',
173      'nysc_year',
174      'nysc_location',
175      'nysc_lga',
176      'former_matric',
177      )
[13545]178PG_OMIT_MANAGE_FIELDS = (
179    'special_application','jamb_subjects_list',) + PG_OMIT_FIELDS
[13546]180PG_OMIT_EDIT_FIELDS = PG_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
[13545]181    'student_id',
182    'notice',
[13546]183    )
[13545]184
[13679]185PTEE_OMIT_FIELDS = (
186    'jamb_age',
187    'jamb_subjects',
188    'jamb_score',
189    'jamb_reg_number',
190    'aggregate'
191    )
192PTEE_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
193    'jamb_subjects_list',) + PTEE_OMIT_FIELDS
194PTEE_OMIT_PDF_FIELDS = PTEE_OMIT_DISPLAY_FIELDS + PTEE_OMIT_FIELDS + (
195      'reg_number','alr_fname', 'alr_no', 'alr_date',
196      'alr_results', 'notice',
197      'nysc_year',
198      'nysc_location',
199      'nysc_lga',
200      'employer',
201      'emp_position',
202      'emp_start',
203      'emp_end',
204      'emp_reason',
205      'employer2',
206      'emp2_position',
207      'emp2_start',
208      'emp2_end',
209      'emp2_reason',
210      'former_matric',
211    )
212PTEE_OMIT_MANAGE_FIELDS = (
213    'special_application','jamb_subjects_list',) + PTEE_OMIT_FIELDS
214PTEE_OMIT_EDIT_FIELDS = PTEE_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
215    'student_id',
216    'notice',
217    )
218
[14150]219UPDATE_OMIT_FIELDS = (
220    'firstname',
221    'middlename',
222    'lastname',
223    'sex',
224    'lga',
225    'course1',
226    )
227
[15113]228MAX_FILE_UPLOAD_SIZE = 1024 * 500
229
230def handle_file_upload(upload, context, view, attr=None):
231    """Handle upload of applicant files.
232
233    Returns `True` in case of success or `False`.
234
235    Please note that file pointer passed in (`upload`) most probably
236    points to end of file when leaving this function.
237    """
238    size = file_size(upload)
239    if size > MAX_FILE_UPLOAD_SIZE:
240        view.flash(_('Uploaded file is too big!'))
241        return False
242    dummy, ext = os.path.splitext(upload.filename)
243    ext.lower()
244    if ext != '.pdf':
245        view.flash(_('pdf file extension expected.'))
246        return False
247    upload.seek(0) # file pointer moved when determining size
248    store = getUtility(IExtFileStore)
249    file_id = IFileStoreNameChooser(context).chooseName(attr=attr)
250    store.createFile(file_id, upload)
251    return True
252
[10298]253class CustomApplicantDisplayFormPage(NigeriaApplicantDisplayFormPage):
254    """A display view for applicant data.
255    """
256
257    @property
[15113]258    def file_links(self):
259        html = ''
260        pdf = getUtility(IExtFileStore).getFileByContext(
261            self.context, attr='stateresult.pdf')
262        if pdf:
[15841]263            html += '<a href="%s">Statement of Result</a>' % self.url(
264                self.context, 'stateresult.pdf')
[15530]265        pdf = getUtility(IExtFileStore).getFileByContext(
266            self.context, attr='verificationdoc.pdf')
267        if pdf:
[15841]268            html += '<a href="%s">Result/Certificate Document</a>' % self.url(
269                self.context, 'verificationdoc.pdf')
[15113]270        return html
271
272    @property
[10298]273    def form_fields(self):
[13538]274        if self.target is not None and self.target == 'trans':
[13544]275            form_fields = grok.AutoFields(ITranscriptApplicant).omit(
[14580]276                'locked', 'suspended')
[13544]277            form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
278            form_fields['perm_address'].custom_widget = BytesDisplayWidget
279            return form_fields
[15530]280        if self.target is not None and self.target == 'ver':
281            form_fields = grok.AutoFields(IVerificationRequest).omit(
282                'locked', 'suspended')
283            form_fields['body_address'].custom_widget = BytesDisplayWidget
284            return form_fields
[15531]285        if self.target is not None and self.target == 'send':
286            form_fields = grok.AutoFields(ISendByEmailRequest).omit(
287                'locked', 'suspended')
288            form_fields['body_address'].custom_widget = BytesDisplayWidget
289            return form_fields
[14304]290        if self.target is not None and self.target == 'cert':
291            form_fields = grok.AutoFields(ICertificateRequest).omit(
[14580]292                'locked', 'suspended')
[15099]293            #form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
294            #form_fields['perm_address'].custom_widget = BytesDisplayWidget
[14304]295            return form_fields
[13538]296        # AAUE is using the same interface for all regular applications.
[11291]297        form_fields = grok.AutoFields(ICustomUGApplicant)
[13538]298        if self.target is not None and self.target.startswith('pg'):
299            for field in PG_OMIT_DISPLAY_FIELDS:
300                form_fields = form_fields.omit(field)
[15521]301        elif self.target is not None and self.target in ('ptee','dsh',):
[13679]302            for field in PTEE_OMIT_DISPLAY_FIELDS:
[10298]303                form_fields = form_fields.omit(field)
[15217]304        elif self.target is not None and self.target in ('bridge', 'ude',):
[14209]305            for field in UDE_OMIT_DISPLAY_FIELDS:
306                form_fields = form_fields.omit(field)
[10298]307        else:
308            for field in UG_OMIT_DISPLAY_FIELDS:
309                form_fields = form_fields.omit(field)
310        form_fields['perm_address'].custom_widget = BytesDisplayWidget
311        form_fields['notice'].custom_widget = BytesDisplayWidget
312        if not getattr(self.context, 'student_id'):
313            form_fields = form_fields.omit('student_id')
314        if not getattr(self.context, 'screening_score'):
315            form_fields = form_fields.omit('screening_score')
[14840]316        if not getattr(self.context, 'screening_venue') or \
317            self.context.state not in ('submitted', 'admitted', 'created'):
[10298]318            form_fields = form_fields.omit('screening_venue')
[14840]319        if not getattr(self.context, 'screening_date') or \
320            self.context.state not in ('submitted', 'admitted', 'created'):
[10298]321            form_fields = form_fields.omit('screening_date')
322        return form_fields
323
[14371]324    def getCourseAdmitted(self):
325        """Return link, title and code in html format to the certificate
326           admitted.
327        """
328        if self.layout.isApplicant():
329            return ''
330        course_admitted = self.context.course_admitted
331        if getattr(course_admitted, '__parent__',None):
332            url = self.url(course_admitted)
333            title = course_admitted.title
334            code = course_admitted.code
335            return '<a href="%s">%s - %s</a>' %(url,code,title)
336        return ''
337
[15530]338    #def update(self):
339    #    super(CustomApplicantDisplayFormPage, self).update()
340    #    #self.extraform_url = self.url(self.context, 'stateresult.pdf')
341    #    return
[15113]342
[13538]343class CustomPDFActionButton(PDFActionButton):
344
345    @property
346    def target_url(self):
[15835]347        if self.context.state in ('initialized', 'started', 'paid'):
348            # or self.context.special or self.view.target in ('trans', 'cert'):
[13540]349            return
350        return self.view.url(self.view.context, self.target)
[13538]351
352
[10298]353class CustomPDFApplicationSlip(NigeriaPDFApplicationSlip):
354
[10311]355    column_two_fields = ('applicant_id', 'reg_number',
356        'firstname', 'middlename', 'lastname', 'sex', 'date_of_birth')
[13679]357    #two_columns_design_fields = [
358    #    'fst_sit_fname', 'fst_sit_no', 'fst_sit_date',
359    #    'fst_sit_type', 'fst_sit_results',
360    #    'scd_sit_fname', 'scd_sit_no', 'scd_sit_date',
361    #    'scd_sit_type', 'scd_sit_results']
[10311]362
[14228]363    def _getCourseAdmittedLink(self, view):
364        return None
365
366    def _getDeptAndFaculty(self):
367        return [None, None]
368
[10301]369    @property
370    def note(self):
[14057]371        note = getattr(self.context.__parent__, 'application_slip_notice', None)
372        if note:
373            return '<br /><br />' + note
[15835]374        if self.target is not None and self.target in (
375            'trans', 'cert', 'ver', 'send'):
376            return
[10301]377        if self.context.sex == 'm':
378            pronoun = 'he'
379        else:
380            pronoun = 'she'
381        return '''
[10897]382The applicant has acknowledged that, if discovered at any time that %s does not possess
383any of the qualifications which %s claims %s has obtained, %s will be expelled from the
[14224]384University not be re-admitted for the same or any other programme, even if %s has
385upgraded previous qualifications or possess additional qualifications.
386
[10331]387''' % (
[10301]388    pronoun, pronoun, pronoun, pronoun, pronoun)
[10298]389
390    @property
391    def form_fields(self):
[13538]392        # AAUE is using the same interface for all regular applications.
[11291]393        form_fields = grok.AutoFields(ICustomUGApplicant)
[13538]394        if self.target is not None and self.target.startswith('pg'):
395            for field in PG_OMIT_PDF_FIELDS:
396                form_fields = form_fields.omit(field)
[15521]397        elif self.target is not None and self.target in ('ptee', 'dsh',):
[13679]398            for field in PTEE_OMIT_PDF_FIELDS:
[10298]399                form_fields = form_fields.omit(field)
[15217]400        elif self.target is not None and self.target in ('bridge', 'ude',):
[14209]401            for field in UDE_OMIT_PDF_FIELDS:
402                form_fields = form_fields.omit(field)
[15835]403        elif self.target is not None and self.target == 'trans':
404            form_fields = grok.AutoFields(ITranscriptApplicant).omit(
405                'locked', 'suspended')
406        elif self.target is not None and self.target == 'ver':
407            form_fields = grok.AutoFields(IVerificationRequest).omit(
408                'locked', 'suspended')
409        elif self.target is not None and self.target == 'send':
410            form_fields = grok.AutoFields(ISendByEmailRequest).omit(
411                'locked', 'suspended')
412        elif self.target is not None and self.target == 'cert':
413            form_fields = grok.AutoFields(ICertificateRequest).omit(
414                'locked', 'suspended')
[10298]415        else:
416            for field in UG_OMIT_PDF_FIELDS:
417                form_fields = form_fields.omit(field)
418        if not getattr(self.context, 'student_id'):
419            form_fields = form_fields.omit('student_id')
420        if not getattr(self.context, 'screening_score'):
421            form_fields = form_fields.omit('screening_score')
422        if not getattr(self.context, 'screening_venue'):
423            form_fields = form_fields.omit('screening_venue')
424        if not getattr(self.context, 'screening_date'):
425            form_fields = form_fields.omit('screening_date')
426        return form_fields
427
428class CustomApplicantManageFormPage(NigeriaApplicantManageFormPage):
429    """A full edit view for applicant data.
430    """
431
432    @property
433    def form_fields(self):
[13538]434        if self.target is not None and self.target == 'trans':
[13544]435            form_fields = grok.AutoFields(ITranscriptApplicant)
[13538]436            form_fields['applicant_id'].for_display = True
437            return form_fields
[14304]438        if self.target is not None and self.target == 'cert':
439            form_fields = grok.AutoFields(ICertificateRequest)
440            form_fields['applicant_id'].for_display = True
441            return form_fields
[15530]442        if self.target is not None and self.target == 'ver':
443            form_fields = grok.AutoFields(IVerificationRequest)
444            form_fields['applicant_id'].for_display = True
445            return form_fields
[15531]446        if self.target is not None and self.target == 'send':
447            form_fields = grok.AutoFields(ISendByEmailRequest)
448            form_fields['applicant_id'].for_display = True
449            return form_fields
[13538]450        # AAUE is using the same interface for all regular applications.
[11291]451        form_fields = grok.AutoFields(ICustomUGApplicant)
[13538]452        if self.target is not None and self.target.startswith('pg'):
453            for field in PG_OMIT_MANAGE_FIELDS:
454                form_fields = form_fields.omit(field)
[15521]455        elif self.target is not None and self.target in ('ptee', 'dsh',):
[13679]456            for field in PTEE_OMIT_MANAGE_FIELDS:
[10298]457                form_fields = form_fields.omit(field)
[15217]458        elif self.target is not None and self.target in ('bridge', 'ude',):
[14209]459            for field in UDE_OMIT_MANAGE_FIELDS:
460                form_fields = form_fields.omit(field)
[10298]461        else:
462            for field in UG_OMIT_MANAGE_FIELDS:
463                form_fields = form_fields.omit(field)
464        form_fields['student_id'].for_display = True
465        form_fields['applicant_id'].for_display = True
466        return form_fields
467
[15113]468    def update(self):
469        super(CustomApplicantManageFormPage, self).update()
470        upload_stateresult = self.request.form.get('form.stateresult', None)
[15530]471        upload_verificationdoc = self.request.form.get('form.verificationdoc', None)
[15113]472        if upload_stateresult:
473            # We got a fresh stateresult upload
474            success = handle_file_upload(
475                upload_stateresult, self.context, self, attr='stateresult.pdf')
476            if success:
477                self.context.writeLogMessage(self, 'saved: stateresult')
478            else:
479                self.upload_success = False
[15530]480        if upload_verificationdoc:
481            # We got a fresh verificationdoc upload
482            success = handle_file_upload(
483                upload_verificationdoc, self.context, self, attr='verificationdoc.pdf')
484            if success:
485                self.context.writeLogMessage(self, 'saved: verificationdoc')
486            else:
487                self.upload_success = False
[15113]488        self.max_file_upload_size = string_from_bytes(MAX_FILE_UPLOAD_SIZE)
489        return
490
[10298]491class CustomApplicantEditFormPage(NigeriaApplicantEditFormPage):
492    """An applicant-centered edit view for applicant data.
493    """
494
[14027]495    def unremovable(self, ticket):
496        return True
497
[15639]498    def dataNotComplete(self, data):
[15099]499        store = getUtility(IExtFileStore)
[15265]500        # Temporarily enable passport upload also for cert and trans
501        # applications.
[15503]502        if self.context.__parent__.with_picture:
[15100]503            if not store.getFileByContext(self.context, attr=u'passport.jpg'):
[15099]504                return _('No passport picture uploaded.')
[15265]505            if not self.target[:4] in ('cert', 'tran') and \
506                not self.request.form.get('confirm_passport', False):
[15099]507                return _('Passport picture confirmation box not ticked.')
[15132]508        if self.target in ('trans', 'cert') and \
[15113]509            not store.getFileByContext(self.context, attr=u'stateresult.pdf'):
510            return _('No statement of result pdf file uploaded.')
[15531]511        if self.target in ('ver',) and \
512            not store.getFileByContext(self.context, attr=u'verificationdoc.pdf'):
513            return _('No pdf file uploaded.')
[15113]514
[15099]515        return False
516
[14027]517    # AAUE applicants never see the 'Remove Selected Tickets' button.
[10298]518    @property
[14027]519    def display_actions(self):
520        # If the form is unlocked, applicants are allowed to save the form
[14029]521        # and remove unused tickets.
522        actions = [[_('Save')], []]
[14027]523        # Only in state started they can also add tickets.
[14822]524        if self.context.state == STARTED:
[14029]525            actions = [[_('Save')],
526                [_('Add online payment ticket')]]
[14027]527        # In state paid, they can submit the data and further add tickets
528        # if the application is special.
[14822]529        elif self.context.special and self.context.state == PAID:
[14027]530            actions = [[_('Save'), _('Finally Submit')],
[14029]531                [_('Add online payment ticket')]]
[14822]532        elif self.context.state == PAID:
[14029]533            actions = [[_('Save'), _('Finally Submit')], []]
[14027]534        return actions
535
536    @property
[10298]537    def form_fields(self):
[13538]538        if self.target is not None and self.target == 'trans':
[13544]539            form_fields = grok.AutoFields(ITranscriptApplicant).omit(
540                'locked', 'suspended')
[13538]541            form_fields['applicant_id'].for_display = True
[14472]542            form_fields['reg_number'].for_display = True
[15276]543            form_fields['place_of_birth'].field.required = True
544            form_fields['date_of_birth'].field.required = True
545            form_fields['nationality'].field.required = True
546            form_fields['email'].field.required = True
547            form_fields['phone'].field.required = True
548            form_fields['perm_address'].field.required = True
549            form_fields['dispatch_address'].field.required = True
550            form_fields['entry_mode'].field.required = True
551            form_fields['entry_session'].field.required = True
552            form_fields['end_session'].field.required = True
553            form_fields['course_studied'].field.required = True
[13538]554            return form_fields
[14304]555        if self.target is not None and self.target == 'cert':
556            form_fields = grok.AutoFields(ICertificateRequest).omit(
557                'locked', 'suspended')
558            form_fields['applicant_id'].for_display = True
[14472]559            form_fields['reg_number'].for_display = True
[15276]560            form_fields['place_of_birth'].field.required = True
561            form_fields['date_of_birth'].field.required = True
562            form_fields['nationality'].field.required = True
563            form_fields['email'].field.required = True
564            form_fields['phone'].field.required = True
565            form_fields['entry_session'].field.required = True
566            form_fields['end_session'].field.required = True
567            form_fields['course_studied'].field.required = True
568            form_fields['certificate_type'].field.required = True
[14696]569            # Additional omissions
570            if self.context.__parent__.code == 'cert5':
571                for field in ('firstname', 'middlename', 'lastname'):
572                    form_fields[field].for_display = True
[14304]573            return form_fields
[15530]574        if self.target is not None and self.target == 'ver':
575            form_fields = grok.AutoFields(IVerificationRequest).omit(
576                'locked', 'suspended')
577            form_fields['applicant_id'].for_display = True
578            return form_fields
[15531]579        if self.target is not None and self.target == 'send':
580            form_fields = grok.AutoFields(ISendByEmailRequest).omit(
581                'locked', 'suspended')
582            form_fields['applicant_id'].for_display = True
583            return form_fields
[13538]584        # AAUE is using the same interface for all regular applications.
[11291]585        form_fields = grok.AutoFields(ICustomUGApplicantEdit)
[13538]586        if self.target is not None and self.target.startswith('pg'):
587            for field in PG_OMIT_EDIT_FIELDS:
588                form_fields = form_fields.omit(field)
[15521]589        elif self.target is not None and self.target in ('ptee','dsh',):
[13679]590            for field in PTEE_OMIT_EDIT_FIELDS:
[10298]591                form_fields = form_fields.omit(field)
[15217]592        elif self.target is not None and self.target in ('bridge', 'ude',):
[14209]593            for field in UDE_OMIT_EDIT_FIELDS:
594                form_fields = form_fields.omit(field)
[10298]595        else:
596            for field in UG_OMIT_EDIT_FIELDS:
597                form_fields = form_fields.omit(field)
[14150]598        # Additional omissions
[14696]599        if self.target is not None and self.target in ('ude', 'utme'):
[14150]600            for field in UPDATE_OMIT_FIELDS:
601                form_fields[field].for_display = True
[10298]602        form_fields['applicant_id'].for_display = True
603        form_fields['reg_number'].for_display = True
604        return form_fields
[10929]605
[15113]606    def update(self):
607        if self.context.locked or (
608            self.context.__parent__.expired and
609            self.context.__parent__.strict_deadline):
610            self.emit_lock_message()
611            return
[15459]612        if getattr(
613            self.context.course1, 'code', 'nocourse') == self.request.form.get(
614            'form.course2', None):
615            self.flash(_('2nd choice course must differ from 1st choice course.'),
616                       type='danger')
617            self.redirect(self.url(self.context))
618            return
619        if getattr(
620            self.context.course1, 'code', 'nocourse') == self.request.form.get(
621            'form.course3', None):
622            self.flash(_('3rd choice course must differ from 1st choice course.'),
623                       type='danger')
624            self.redirect(self.url(self.context))
625            return
[15113]626        super(CustomApplicantEditFormPage, self).update()
627        upload_stateresult = self.request.form.get('form.stateresult', None)
[15530]628        upload_verificationdoc = self.request.form.get('form.verificationdoc', None)
[15113]629        if upload_stateresult:
630            # We got a fresh stateresult upload
631            success = handle_file_upload(
632                upload_stateresult, self.context, self, attr='stateresult.pdf')
633            if not success:
634                self.upload_success = False
[15530]635        if upload_verificationdoc:
636            # We got a fresh verificationdoc upload
637            success = handle_file_upload(
638                upload_verificationdoc, self.context, self, attr='verificationdoc.pdf')
639            if not success:
640                self.upload_success = False
[15113]641        self.max_file_upload_size = string_from_bytes(MAX_FILE_UPLOAD_SIZE)
642        return
643
[10929]644class CustomApplicantRegistrationPage(NigeriaApplicantRegistrationPage):
645    """Captcha'd registration page for applicants.
646    """
647
[14460]648    @property
649    def form_fields(self):
650        form_fields = None
651        if self.context.mode == 'update':
652            form_fields = grok.AutoFields(IApplicantRegisterUpdate).select(
653                'lastname','reg_number','email')
[14465]654            target = getattr(self.context, 'prefix', None)
[14460]655            if target in ('trans', 'cert'):
656                form_fields.get('reg_number').field.title = u'Matriculation Number'
657        else: #if self.context.mode == 'create':
658            form_fields = grok.AutoFields(ICustomUGApplicantEdit).select(
659                'firstname', 'middlename', 'lastname', 'email', 'phone')
660        return form_fields
661
[10929]662    def _redirect(self, email, password, applicant_id):
663        # Forward email and credentials to landing page.
664        self.redirect(self.url(self.context, 'registration_complete',
665            data = dict(email=email, password=password,
666            applicant_id=applicant_id)))
[11755]667        return
668
[14579]669    @property
670    def _postfix(self):
671        """Alumni records have to be imported into several containers.
672        Therefore a string must be added to their registration number
673        to make it unique.
674        """
675        if self.context.prefix in ('trans', 'cert'):
676            return self.context.code
677        return ''
678
[11755]679class CustomExportPDFPaymentSlipPage(NigeriaExportPDFPaymentSlipPage):
680
681    @property
682    def payment_slip_download_warning(self):
[13422]683        return ''
684
685class CustomApplicantCheckStatusPage(ApplicantCheckStatusPage):
686    """Captcha'd status checking page for applicants.
687    """
688    grok.template('applicantcheckstatus')
[13996]689
[14822]690class ScreeningInvitationActionButton(ManageActionButton):
[13997]691    grok.order(8) # This button should always be the last one.
692    grok.context(ICustomApplicant)
693    grok.view(CustomApplicantDisplayFormPage)
694    grok.require('waeup.viewApplication')
695    icon = 'actionicon_pdf.png'
696    text = _('Download screening invitation letter')
697    target = 'screening_invitation.pdf'
[13996]698
[13997]699    @property
700    def target_url(self):
[14822]701        if not self.context.screening_date or not self.context.state in (
[14824]702            'submitted', 'admitted', 'created'):
[13997]703            return ''
704        return self.view.url(self.view.context, self.target)
705
[13996]706class ExportScreeningInvitationLetter(UtilityView, grok.View):
707    """Deliver a slip with only screening data.
708    This form page is available only in AAUE.
709    """
[13997]710    grok.context(ICustomApplicant)
[13996]711    grok.name('screening_invitation.pdf')
712    grok.require('waeup.viewApplication')
713    prefix = 'form'
714
715    label = u'Screening Invitation Letter'
716
717    form_fields = []
718
719    @property
720    def note(self):
721        if self.context.screening_date:
[13999]722            year = self.context.__parent__.year
723            session = '%s/%s' % (year, year + 1)
724            sdate = self.context.screening_date
725            stime = ''
726            if '@' in self.context.screening_date:
727                sdate = self.context.screening_date.split('@')[0].strip()
728                stime = self.context.screening_date.split('@')[1].strip()
[13996]729            return """
730<br /><br /><br /><br /><font size='12'>
731Dear %s,
732<br /><br />
[13999]733You are invited to the Ambrose Alli University %s Admissions Screening Exercise.
[13996]734<br /><br />
[13999]735<strong>Date: %s
[13996]736<br /><br />
[13999]737Time: %s
738<br /><br />
[13997]739Venue: %s
740</strong>
[13996]741<br /><br />
[14015]742Please bring this letter of invitation and the downloaded application form along with you on your screening date.
743<br /><br />
744You are expected to be available 30 minutes before the commencement of your Screening.
[13996]745</font>
746
[13999]747""" % (
748       self.context.display_fullname,
749       session,
750       sdate,
751       stime,
[13996]752       self.context.screening_venue)
753        return
754
755    @property
756    def title(self):
757        return None
758
759    def update(self):
[14822]760        if not self.context.screening_date or not self.context.state in (
[14824]761            'submitted', 'admitted', 'created'):
[13996]762            self.flash(_('Forbidden'), type="warning")
763            self.redirect(self.url(self.context))
764
765    def render(self):
766        applicantview = ApplicantBaseDisplayFormPage(self.context, self.request)
767        students_utils = getUtility(IStudentsUtils)
768        return students_utils.renderPDF(self,'screening_data.pdf',
[14015]769            self.context, applicantview, note=self.note)
[15113]770
771class StateResult(grok.View):
772    """Renders the pdf form extension for applicants.
773    """
774    grok.name('stateresult.pdf')
775    grok.context(ICustomApplicant)
776    grok.require('waeup.viewApplication')
777
778    def render(self):
779        pdf = getUtility(IExtFileStore).getFileByContext(
780            self.context, attr='stateresult.pdf')
781        self.response.setHeader('Content-Type', 'application/pdf')
[15530]782        return pdf
783
784class VerificationDoc(grok.View):
785    """Renders the pdf form extension for applicants.
786    """
787    grok.name('verificationdoc.pdf')
788    grok.context(ICustomApplicant)
789    grok.require('waeup.viewApplication')
790
791    def render(self):
792        pdf = getUtility(IExtFileStore).getFileByContext(
793            self.context, attr='verificationdoc.pdf')
794        self.response.setHeader('Content-Type', 'application/pdf')
[15113]795        return pdf
Note: See TracBrowser for help on using the repository browser.