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

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

Implement "Scanned Result/Certificate? via email" application form.

  • Property svn:keywords set to Id
File size: 29.7 KB
Line 
1## $Id: browser.py 15531 2019-07-31 11:55:46Z 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
22from zope.component import getUtility, getAdapter
23from zope.i18n import translate
24from hurry.workflow.interfaces import IWorkflowState
25from waeup.kofa.interfaces import (
26    IExtFileStore, IFileStoreNameChooser, IKofaUtils)
27from zope.formlib.textwidgets import BytesDisplayWidget
28from waeup.kofa.utils.helpers import string_from_bytes, file_size
29from waeup.kofa.applicants.browser import (
30    ApplicantCheckStatusPage, ApplicantBaseDisplayFormPage)
31from waeup.kofa.applicants.workflow import STARTED, PAID
32from waeup.kofa.applicants.viewlets import PDFActionButton
33from waeup.kofa.applicants.interfaces import IApplicantRegisterUpdate
34from waeup.kofa.browser.layout import UtilityView
35from waeup.kofa.students.interfaces import IStudentsUtils
36from waeup.kofa.interfaces import IPDF
37from waeup.kofa.browser.viewlets import ManageActionButton
38from waeup.aaue.interfaces import MessageFactory as _
39from kofacustom.nigeria.applicants.browser import (
40    NigeriaApplicantDisplayFormPage,
41    NigeriaApplicantManageFormPage,
42    NigeriaApplicantEditFormPage,
43    NigeriaPDFApplicationSlip,
44    NigeriaApplicantRegistrationPage,
45    NigeriaExportPDFPaymentSlipPage,
46    )
47from kofacustom.nigeria.applicants.interfaces import OMIT_DISPLAY_FIELDS
48from waeup.aaue.applicants.interfaces import (
49    ICustomUGApplicant,
50    ICustomUGApplicantEdit,
51    ITranscriptApplicant,
52    ICertificateRequest,
53    ICustomApplicant,
54    IVerificationRequest,
55    ISendByEmailRequest
56    )
57
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',
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',
79      )
80UG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
81    'jamb_subjects_list', 'master_sheet_number') + UG_OMIT_FIELDS
82UG_OMIT_PDF_FIELDS = UG_OMIT_DISPLAY_FIELDS + UG_OMIT_FIELDS + (
83      'alr_fname', 'alr_no', 'alr_date',
84      'alr_results', 'notice')
85UG_OMIT_MANAGE_FIELDS = (
86    'special_application','jamb_subjects_list',) + UG_OMIT_FIELDS
87UG_OMIT_EDIT_FIELDS = UG_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
88    'student_id',
89    'notice',
90    'jamb_age',
91    'jamb_subjects',
92    'jamb_score',
93    'jamb_reg_number',
94    'aggregate',
95    'master_sheet_number',
96    'screening_venue',
97    'screening_score',
98    'screening_date'
99    )
100
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 + (
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')
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
142#UG_OMIT_PDF_FIELDS = tuple([
143#    element for element in UG_OMIT_PDF_FIELDS if not element == 'phone'])
144
145#UG_OMIT_PDF_FIELDS += (
146#      'reg_number','alr_fname', 'alr_no', 'alr_date',
147#      'alr_results', 'notice'
148#      )
149
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',
161    #'programme_type',
162    'jamb_age',
163    'jamb_subjects',
164    'jamb_score',
165    'jamb_reg_number',
166    'aggregate'
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',
172      'alr_results', 'notice',
173      'nysc_year',
174      'nysc_location',
175      'nysc_lga',
176      'former_matric',
177      )
178PG_OMIT_MANAGE_FIELDS = (
179    'special_application','jamb_subjects_list',) + PG_OMIT_FIELDS
180PG_OMIT_EDIT_FIELDS = PG_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
181    'student_id',
182    'notice',
183    )
184
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
219UPDATE_OMIT_FIELDS = (
220    'firstname',
221    'middlename',
222    'lastname',
223    'sex',
224    'lga',
225    'course1',
226    )
227
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
253class CustomApplicantDisplayFormPage(NigeriaApplicantDisplayFormPage):
254    """A display view for applicant data.
255    """
256
257    @property
258    def file_links(self):
259        html = ''
260        pdf = getUtility(IExtFileStore).getFileByContext(
261            self.context, attr='stateresult.pdf')
262        if pdf:
263            html += '<a href="stateresult.pdf">Statement of Result</a>'
264        pdf = getUtility(IExtFileStore).getFileByContext(
265            self.context, attr='verificationdoc.pdf')
266        if pdf:
267            html += '<a href="verificationdoc.pdf">Result/Certificate Document</a>'
268        return html
269
270    @property
271    def form_fields(self):
272        if self.target is not None and self.target == 'trans':
273            form_fields = grok.AutoFields(ITranscriptApplicant).omit(
274                'locked', 'suspended')
275            form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
276            form_fields['perm_address'].custom_widget = BytesDisplayWidget
277            return form_fields
278        if self.target is not None and self.target == 'ver':
279            form_fields = grok.AutoFields(IVerificationRequest).omit(
280                'locked', 'suspended')
281            form_fields['body_address'].custom_widget = BytesDisplayWidget
282            return form_fields
283        if self.target is not None and self.target == 'send':
284            form_fields = grok.AutoFields(ISendByEmailRequest).omit(
285                'locked', 'suspended')
286            form_fields['body_address'].custom_widget = BytesDisplayWidget
287            return form_fields
288        if self.target is not None and self.target == 'cert':
289            form_fields = grok.AutoFields(ICertificateRequest).omit(
290                'locked', 'suspended')
291            #form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
292            #form_fields['perm_address'].custom_widget = BytesDisplayWidget
293            return form_fields
294        # AAUE is using the same interface for all regular applications.
295        form_fields = grok.AutoFields(ICustomUGApplicant)
296        if self.target is not None and self.target.startswith('pg'):
297            for field in PG_OMIT_DISPLAY_FIELDS:
298                form_fields = form_fields.omit(field)
299        elif self.target is not None and self.target in ('ptee','dsh',):
300            for field in PTEE_OMIT_DISPLAY_FIELDS:
301                form_fields = form_fields.omit(field)
302        elif self.target is not None and self.target in ('bridge', 'ude',):
303            for field in UDE_OMIT_DISPLAY_FIELDS:
304                form_fields = form_fields.omit(field)
305        else:
306            for field in UG_OMIT_DISPLAY_FIELDS:
307                form_fields = form_fields.omit(field)
308        form_fields['perm_address'].custom_widget = BytesDisplayWidget
309        form_fields['notice'].custom_widget = BytesDisplayWidget
310        if not getattr(self.context, 'student_id'):
311            form_fields = form_fields.omit('student_id')
312        if not getattr(self.context, 'screening_score'):
313            form_fields = form_fields.omit('screening_score')
314        if not getattr(self.context, 'screening_venue') or \
315            self.context.state not in ('submitted', 'admitted', 'created'):
316            form_fields = form_fields.omit('screening_venue')
317        if not getattr(self.context, 'screening_date') or \
318            self.context.state not in ('submitted', 'admitted', 'created'):
319            form_fields = form_fields.omit('screening_date')
320        return form_fields
321
322    def getCourseAdmitted(self):
323        """Return link, title and code in html format to the certificate
324           admitted.
325        """
326        if self.layout.isApplicant():
327            return ''
328        course_admitted = self.context.course_admitted
329        if getattr(course_admitted, '__parent__',None):
330            url = self.url(course_admitted)
331            title = course_admitted.title
332            code = course_admitted.code
333            return '<a href="%s">%s - %s</a>' %(url,code,title)
334        return ''
335
336    #def update(self):
337    #    super(CustomApplicantDisplayFormPage, self).update()
338    #    #self.extraform_url = self.url(self.context, 'stateresult.pdf')
339    #    return
340
341class CustomPDFActionButton(PDFActionButton):
342
343    @property
344    def target_url(self):
345        if self.context.state in ('initialized', 'started', 'paid') \
346            or self.context.special or self.view.target in ('trans', 'cert'):
347            return
348        return self.view.url(self.view.context, self.target)
349
350
351class CustomPDFApplicationSlip(NigeriaPDFApplicationSlip):
352
353    column_two_fields = ('applicant_id', 'reg_number',
354        'firstname', 'middlename', 'lastname', 'sex', 'date_of_birth')
355    #two_columns_design_fields = [
356    #    'fst_sit_fname', 'fst_sit_no', 'fst_sit_date',
357    #    'fst_sit_type', 'fst_sit_results',
358    #    'scd_sit_fname', 'scd_sit_no', 'scd_sit_date',
359    #    'scd_sit_type', 'scd_sit_results']
360
361    def _getCourseAdmittedLink(self, view):
362        return None
363
364    def _getDeptAndFaculty(self):
365        return [None, None]
366
367    @property
368    def note(self):
369        note = getattr(self.context.__parent__, 'application_slip_notice', None)
370        if note:
371            return '<br /><br />' + note
372        if self.context.sex == 'm':
373            pronoun = 'he'
374        else:
375            pronoun = 'she'
376        return '''
377The applicant has acknowledged that, if discovered at any time that %s does not possess
378any of the qualifications which %s claims %s has obtained, %s will be expelled from the
379University not be re-admitted for the same or any other programme, even if %s has
380upgraded previous qualifications or possess additional qualifications.
381
382''' % (
383    pronoun, pronoun, pronoun, pronoun, pronoun)
384
385    @property
386    def form_fields(self):
387        # AAUE is using the same interface for all regular applications.
388        form_fields = grok.AutoFields(ICustomUGApplicant)
389        if self.target is not None and self.target.startswith('pg'):
390            for field in PG_OMIT_PDF_FIELDS:
391                form_fields = form_fields.omit(field)
392        elif self.target is not None and self.target in ('ptee', 'dsh',):
393            for field in PTEE_OMIT_PDF_FIELDS:
394                form_fields = form_fields.omit(field)
395        elif self.target is not None and self.target in ('bridge', 'ude',):
396            for field in UDE_OMIT_PDF_FIELDS:
397                form_fields = form_fields.omit(field)
398        else:
399            for field in UG_OMIT_PDF_FIELDS:
400                form_fields = form_fields.omit(field)
401        if not getattr(self.context, 'student_id'):
402            form_fields = form_fields.omit('student_id')
403        if not getattr(self.context, 'screening_score'):
404            form_fields = form_fields.omit('screening_score')
405        if not getattr(self.context, 'screening_venue'):
406            form_fields = form_fields.omit('screening_venue')
407        if not getattr(self.context, 'screening_date'):
408            form_fields = form_fields.omit('screening_date')
409        return form_fields
410
411class CustomApplicantManageFormPage(NigeriaApplicantManageFormPage):
412    """A full edit view for applicant data.
413    """
414
415    @property
416    def form_fields(self):
417        if self.target is not None and self.target == 'trans':
418            form_fields = grok.AutoFields(ITranscriptApplicant)
419            form_fields['applicant_id'].for_display = True
420            return form_fields
421        if self.target is not None and self.target == 'cert':
422            form_fields = grok.AutoFields(ICertificateRequest)
423            form_fields['applicant_id'].for_display = True
424            return form_fields
425        if self.target is not None and self.target == 'ver':
426            form_fields = grok.AutoFields(IVerificationRequest)
427            form_fields['applicant_id'].for_display = True
428            return form_fields
429        if self.target is not None and self.target == 'send':
430            form_fields = grok.AutoFields(ISendByEmailRequest)
431            form_fields['applicant_id'].for_display = True
432            return form_fields
433        # AAUE is using the same interface for all regular applications.
434        form_fields = grok.AutoFields(ICustomUGApplicant)
435        if self.target is not None and self.target.startswith('pg'):
436            for field in PG_OMIT_MANAGE_FIELDS:
437                form_fields = form_fields.omit(field)
438        elif self.target is not None and self.target in ('ptee', 'dsh',):
439            for field in PTEE_OMIT_MANAGE_FIELDS:
440                form_fields = form_fields.omit(field)
441        elif self.target is not None and self.target in ('bridge', 'ude',):
442            for field in UDE_OMIT_MANAGE_FIELDS:
443                form_fields = form_fields.omit(field)
444        else:
445            for field in UG_OMIT_MANAGE_FIELDS:
446                form_fields = form_fields.omit(field)
447        form_fields['student_id'].for_display = True
448        form_fields['applicant_id'].for_display = True
449        return form_fields
450
451    def update(self):
452        super(CustomApplicantManageFormPage, self).update()
453        upload_stateresult = self.request.form.get('form.stateresult', None)
454        upload_verificationdoc = self.request.form.get('form.verificationdoc', None)
455        if upload_stateresult:
456            # We got a fresh stateresult upload
457            success = handle_file_upload(
458                upload_stateresult, self.context, self, attr='stateresult.pdf')
459            if success:
460                self.context.writeLogMessage(self, 'saved: stateresult')
461            else:
462                self.upload_success = False
463        if upload_verificationdoc:
464            # We got a fresh verificationdoc upload
465            success = handle_file_upload(
466                upload_verificationdoc, self.context, self, attr='verificationdoc.pdf')
467            if success:
468                self.context.writeLogMessage(self, 'saved: verificationdoc')
469            else:
470                self.upload_success = False
471        self.max_file_upload_size = string_from_bytes(MAX_FILE_UPLOAD_SIZE)
472        return
473
474class CustomApplicantEditFormPage(NigeriaApplicantEditFormPage):
475    """An applicant-centered edit view for applicant data.
476    """
477
478    def unremovable(self, ticket):
479        return True
480
481    def dataNotComplete(self):
482        store = getUtility(IExtFileStore)
483        # Temporarily enable passport upload also for cert and trans
484        # applications.
485        if self.context.__parent__.with_picture:
486            if not store.getFileByContext(self.context, attr=u'passport.jpg'):
487                return _('No passport picture uploaded.')
488            if not self.target[:4] in ('cert', 'tran') and \
489                not self.request.form.get('confirm_passport', False):
490                return _('Passport picture confirmation box not ticked.')
491        if self.target in ('trans', 'cert') and \
492            not store.getFileByContext(self.context, attr=u'stateresult.pdf'):
493            return _('No statement of result pdf file uploaded.')
494        if self.target in ('ver',) and \
495            not store.getFileByContext(self.context, attr=u'verificationdoc.pdf'):
496            return _('No pdf file uploaded.')
497
498        return False
499
500    # AAUE applicants never see the 'Remove Selected Tickets' button.
501    @property
502    def display_actions(self):
503        # If the form is unlocked, applicants are allowed to save the form
504        # and remove unused tickets.
505        actions = [[_('Save')], []]
506        # Only in state started they can also add tickets.
507        if self.context.state == STARTED:
508            actions = [[_('Save')],
509                [_('Add online payment ticket')]]
510        # In state paid, they can submit the data and further add tickets
511        # if the application is special.
512        elif self.context.special and self.context.state == PAID:
513            actions = [[_('Save'), _('Finally Submit')],
514                [_('Add online payment ticket')]]
515        elif self.context.state == PAID:
516            actions = [[_('Save'), _('Finally Submit')], []]
517        return actions
518
519    @property
520    def form_fields(self):
521        if self.target is not None and self.target == 'trans':
522            form_fields = grok.AutoFields(ITranscriptApplicant).omit(
523                'locked', 'suspended')
524            form_fields['applicant_id'].for_display = True
525            form_fields['reg_number'].for_display = True
526            form_fields['place_of_birth'].field.required = True
527            form_fields['date_of_birth'].field.required = True
528            form_fields['nationality'].field.required = True
529            form_fields['email'].field.required = True
530            form_fields['phone'].field.required = True
531            form_fields['perm_address'].field.required = True
532            form_fields['dispatch_address'].field.required = True
533            form_fields['entry_mode'].field.required = True
534            form_fields['entry_session'].field.required = True
535            form_fields['end_session'].field.required = True
536            form_fields['course_studied'].field.required = True
537            return form_fields
538        if self.target is not None and self.target == 'cert':
539            form_fields = grok.AutoFields(ICertificateRequest).omit(
540                'locked', 'suspended')
541            form_fields['applicant_id'].for_display = True
542            form_fields['reg_number'].for_display = True
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['entry_session'].field.required = True
549            form_fields['end_session'].field.required = True
550            form_fields['course_studied'].field.required = True
551            form_fields['certificate_type'].field.required = True
552            # Additional omissions
553            if self.context.__parent__.code == 'cert5':
554                for field in ('firstname', 'middlename', 'lastname'):
555                    form_fields[field].for_display = True
556            return form_fields
557        if self.target is not None and self.target == 'ver':
558            form_fields = grok.AutoFields(IVerificationRequest).omit(
559                'locked', 'suspended')
560            form_fields['applicant_id'].for_display = True
561            return form_fields
562        if self.target is not None and self.target == 'send':
563            form_fields = grok.AutoFields(ISendByEmailRequest).omit(
564                'locked', 'suspended')
565            form_fields['applicant_id'].for_display = True
566            return form_fields
567        # AAUE is using the same interface for all regular applications.
568        form_fields = grok.AutoFields(ICustomUGApplicantEdit)
569        if self.target is not None and self.target.startswith('pg'):
570            for field in PG_OMIT_EDIT_FIELDS:
571                form_fields = form_fields.omit(field)
572        elif self.target is not None and self.target in ('ptee','dsh',):
573            for field in PTEE_OMIT_EDIT_FIELDS:
574                form_fields = form_fields.omit(field)
575        elif self.target is not None and self.target in ('bridge', 'ude',):
576            for field in UDE_OMIT_EDIT_FIELDS:
577                form_fields = form_fields.omit(field)
578        else:
579            for field in UG_OMIT_EDIT_FIELDS:
580                form_fields = form_fields.omit(field)
581        # Additional omissions
582        if self.target is not None and self.target in ('ude', 'utme'):
583            for field in UPDATE_OMIT_FIELDS:
584                form_fields[field].for_display = True
585        form_fields['applicant_id'].for_display = True
586        form_fields['reg_number'].for_display = True
587        return form_fields
588
589    def update(self):
590        if self.context.locked or (
591            self.context.__parent__.expired and
592            self.context.__parent__.strict_deadline):
593            self.emit_lock_message()
594            return
595        if getattr(
596            self.context.course1, 'code', 'nocourse') == self.request.form.get(
597            'form.course2', None):
598            self.flash(_('2nd choice course must differ from 1st choice course.'),
599                       type='danger')
600            self.redirect(self.url(self.context))
601            return
602        if getattr(
603            self.context.course1, 'code', 'nocourse') == self.request.form.get(
604            'form.course3', None):
605            self.flash(_('3rd choice course must differ from 1st choice course.'),
606                       type='danger')
607            self.redirect(self.url(self.context))
608            return
609        super(CustomApplicantEditFormPage, self).update()
610        upload_stateresult = self.request.form.get('form.stateresult', None)
611        upload_verificationdoc = self.request.form.get('form.verificationdoc', None)
612        if upload_stateresult:
613            # We got a fresh stateresult upload
614            success = handle_file_upload(
615                upload_stateresult, self.context, self, attr='stateresult.pdf')
616            if not success:
617                self.upload_success = False
618        if upload_verificationdoc:
619            # We got a fresh verificationdoc upload
620            success = handle_file_upload(
621                upload_verificationdoc, self.context, self, attr='verificationdoc.pdf')
622            if not success:
623                self.upload_success = False
624        self.max_file_upload_size = string_from_bytes(MAX_FILE_UPLOAD_SIZE)
625        return
626
627class CustomApplicantRegistrationPage(NigeriaApplicantRegistrationPage):
628    """Captcha'd registration page for applicants.
629    """
630
631    @property
632    def form_fields(self):
633        form_fields = None
634        if self.context.mode == 'update':
635            form_fields = grok.AutoFields(IApplicantRegisterUpdate).select(
636                'lastname','reg_number','email')
637            target = getattr(self.context, 'prefix', None)
638            if target in ('trans', 'cert'):
639                form_fields.get('reg_number').field.title = u'Matriculation Number'
640        else: #if self.context.mode == 'create':
641            form_fields = grok.AutoFields(ICustomUGApplicantEdit).select(
642                'firstname', 'middlename', 'lastname', 'email', 'phone')
643        return form_fields
644
645    def _redirect(self, email, password, applicant_id):
646        # Forward email and credentials to landing page.
647        self.redirect(self.url(self.context, 'registration_complete',
648            data = dict(email=email, password=password,
649            applicant_id=applicant_id)))
650        return
651
652    @property
653    def _postfix(self):
654        """Alumni records have to be imported into several containers.
655        Therefore a string must be added to their registration number
656        to make it unique.
657        """
658        if self.context.prefix in ('trans', 'cert'):
659            return self.context.code
660        return ''
661
662class CustomExportPDFPaymentSlipPage(NigeriaExportPDFPaymentSlipPage):
663
664    @property
665    def payment_slip_download_warning(self):
666        return ''
667
668class CustomApplicantCheckStatusPage(ApplicantCheckStatusPage):
669    """Captcha'd status checking page for applicants.
670    """
671    grok.template('applicantcheckstatus')
672
673class ScreeningInvitationActionButton(ManageActionButton):
674    grok.order(8) # This button should always be the last one.
675    grok.context(ICustomApplicant)
676    grok.view(CustomApplicantDisplayFormPage)
677    grok.require('waeup.viewApplication')
678    icon = 'actionicon_pdf.png'
679    text = _('Download screening invitation letter')
680    target = 'screening_invitation.pdf'
681
682    @property
683    def target_url(self):
684        if not self.context.screening_date or not self.context.state in (
685            'submitted', 'admitted', 'created'):
686            return ''
687        return self.view.url(self.view.context, self.target)
688
689class ExportScreeningInvitationLetter(UtilityView, grok.View):
690    """Deliver a slip with only screening data.
691    This form page is available only in AAUE.
692    """
693    grok.context(ICustomApplicant)
694    grok.name('screening_invitation.pdf')
695    grok.require('waeup.viewApplication')
696    prefix = 'form'
697
698    label = u'Screening Invitation Letter'
699
700    form_fields = []
701
702    @property
703    def note(self):
704        if self.context.screening_date:
705            year = self.context.__parent__.year
706            session = '%s/%s' % (year, year + 1)
707            sdate = self.context.screening_date
708            stime = ''
709            if '@' in self.context.screening_date:
710                sdate = self.context.screening_date.split('@')[0].strip()
711                stime = self.context.screening_date.split('@')[1].strip()
712            return """
713<br /><br /><br /><br /><font size='12'>
714Dear %s,
715<br /><br />
716You are invited to the Ambrose Alli University %s Admissions Screening Exercise.
717<br /><br />
718<strong>Date: %s
719<br /><br />
720Time: %s
721<br /><br />
722Venue: %s
723</strong>
724<br /><br />
725Please bring this letter of invitation and the downloaded application form along with you on your screening date.
726<br /><br />
727You are expected to be available 30 minutes before the commencement of your Screening.
728</font>
729
730""" % (
731       self.context.display_fullname,
732       session,
733       sdate,
734       stime,
735       self.context.screening_venue)
736        return
737
738    @property
739    def title(self):
740        return None
741
742    def update(self):
743        if not self.context.screening_date or not self.context.state in (
744            'submitted', 'admitted', 'created'):
745            self.flash(_('Forbidden'), type="warning")
746            self.redirect(self.url(self.context))
747
748    def render(self):
749        applicantview = ApplicantBaseDisplayFormPage(self.context, self.request)
750        students_utils = getUtility(IStudentsUtils)
751        return students_utils.renderPDF(self,'screening_data.pdf',
752            self.context, applicantview, note=self.note)
753
754class StateResult(grok.View):
755    """Renders the pdf form extension for applicants.
756    """
757    grok.name('stateresult.pdf')
758    grok.context(ICustomApplicant)
759    grok.require('waeup.viewApplication')
760
761    def render(self):
762        pdf = getUtility(IExtFileStore).getFileByContext(
763            self.context, attr='stateresult.pdf')
764        self.response.setHeader('Content-Type', 'application/pdf')
765        return pdf
766
767class VerificationDoc(grok.View):
768    """Renders the pdf form extension for applicants.
769    """
770    grok.name('verificationdoc.pdf')
771    grok.context(ICustomApplicant)
772    grok.require('waeup.viewApplication')
773
774    def render(self):
775        pdf = getUtility(IExtFileStore).getFileByContext(
776            self.context, attr='verificationdoc.pdf')
777        self.response.setHeader('Content-Type', 'application/pdf')
778        return pdf
Note: See TracBrowser for help on using the repository browser.