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

Last change on this file since 15098 was 15091, checked in by Henrik Bettermann, 7 years ago

Include "Advanced Level Record" to the printed pdf.
Remove "2nd Higher Education Record" and "3rd Higher Education Record" from the pdf forms.

  • Property svn:keywords set to Id
File size: 21.0 KB
Line 
1## $Id: browser.py 15091 2018-07-28 05:25:26Z 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    )
55
56UG_OMIT_FIELDS = (
57      'hq_type', 'hq_fname', 'hq_matric_no',
58      'hq_degree', 'hq_school', 'hq_session', 'hq_disc',
59      'hq_type2', 'hq_fname2', 'hq_matric_no2',
60      'hq_degree2', 'hq_school2', 'hq_session2', 'hq_disc2',
61      'hq_type3', 'hq_fname3', 'hq_matric_no3',
62      'hq_degree3', 'hq_school3', 'hq_session3', 'hq_disc3',
63      'nysc_year',
64      'nysc_location',
65      'nysc_lga',
66      'employer',
67      'emp_position',
68      'emp_start',
69      'emp_end',
70      'emp_reason',
71      'employer2',
72      'emp2_position',
73      'emp2_start',
74      'emp2_end',
75      'emp2_reason',
76      'former_matric',
77      )
78UG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
79    'jamb_subjects_list', 'master_sheet_number') + UG_OMIT_FIELDS
80UG_OMIT_PDF_FIELDS = UG_OMIT_DISPLAY_FIELDS + UG_OMIT_FIELDS + (
81      'alr_fname', 'alr_no', 'alr_date',
82      'alr_results', 'notice')
83UG_OMIT_MANAGE_FIELDS = (
84    'special_application','jamb_subjects_list',) + UG_OMIT_FIELDS
85UG_OMIT_EDIT_FIELDS = UG_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
86    'student_id',
87    'notice',
88    'jamb_age',
89    'jamb_subjects',
90    'jamb_score',
91    'jamb_reg_number',
92    'aggregate',
93    'master_sheet_number',
94    'screening_venue',
95    'screening_score',
96    'screening_date'
97    )
98
99UDE_OMIT_FIELDS = (
100      'nysc_year',
101      'nysc_location',
102      'nysc_lga',
103      'employer',
104      'emp_position',
105      'emp_start',
106      'emp_end',
107      'emp_reason',
108      'employer2',
109      'emp2_position',
110      'emp2_start',
111      'emp2_end',
112      'emp2_reason',
113      'former_matric',
114      )
115UDE_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
116    'jamb_subjects_list', 'master_sheet_number') + UDE_OMIT_FIELDS
117UDE_OMIT_PDF_FIELDS = UDE_OMIT_DISPLAY_FIELDS + UDE_OMIT_FIELDS + (
118      #'alr_fname', 'alr_no', 'alr_date', 'alr_results',
119      'hq_type2', 'hq_fname2', 'hq_matric_no2',
120      'hq_degree2', 'hq_school2', 'hq_session2', 'hq_disc2',
121      'hq_type3', 'hq_fname3', 'hq_matric_no3',
122      'hq_degree3', 'hq_school3', 'hq_session3', 'hq_disc3',
123      'notice')
124UDE_OMIT_MANAGE_FIELDS = (
125    'special_application','jamb_subjects_list',) + UDE_OMIT_FIELDS
126UDE_OMIT_EDIT_FIELDS = UDE_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
127    'student_id',
128    'notice',
129    'jamb_age',
130    'jamb_subjects',
131    'jamb_score',
132    'jamb_reg_number',
133    'aggregate',
134    'master_sheet_number',
135    'screening_venue',
136    'screening_score',
137    'screening_date'
138    )
139
140#UG_OMIT_PDF_FIELDS = tuple([
141#    element for element in UG_OMIT_PDF_FIELDS if not element == 'phone'])
142
143#UG_OMIT_PDF_FIELDS += (
144#      'reg_number','alr_fname', 'alr_no', 'alr_date',
145#      'alr_results', 'notice'
146#      )
147
148PG_OMIT_FIELDS = (
149    'fst_sit_fname',
150    'fst_sit_no',
151    'fst_sit_date',
152    'fst_sit_type',
153    'fst_sit_results',
154    'scd_sit_fname',
155    'scd_sit_no',
156    'scd_sit_date',
157    'scd_sit_type',
158    'scd_sit_results',
159    #'programme_type',
160    'jamb_age',
161    'jamb_subjects',
162    'jamb_score',
163    'jamb_reg_number',
164    'aggregate'
165    )
166PG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
167    'jamb_subjects_list',) + PG_OMIT_FIELDS
168PG_OMIT_PDF_FIELDS = PG_OMIT_DISPLAY_FIELDS + PG_OMIT_FIELDS + (
169      'reg_number','alr_fname', 'alr_no', 'alr_date',
170      'alr_results', 'notice',
171      'nysc_year',
172      'nysc_location',
173      'nysc_lga',
174      'former_matric',
175      )
176PG_OMIT_MANAGE_FIELDS = (
177    'special_application','jamb_subjects_list',) + PG_OMIT_FIELDS
178PG_OMIT_EDIT_FIELDS = PG_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
179    'student_id',
180    'notice',
181    )
182
183PTEE_OMIT_FIELDS = (
184    'jamb_age',
185    'jamb_subjects',
186    'jamb_score',
187    'jamb_reg_number',
188    'aggregate'
189    )
190PTEE_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
191    'jamb_subjects_list',) + PTEE_OMIT_FIELDS
192PTEE_OMIT_PDF_FIELDS = PTEE_OMIT_DISPLAY_FIELDS + PTEE_OMIT_FIELDS + (
193      'reg_number','alr_fname', 'alr_no', 'alr_date',
194      'alr_results', 'notice',
195      'nysc_year',
196      'nysc_location',
197      'nysc_lga',
198      'employer',
199      'emp_position',
200      'emp_start',
201      'emp_end',
202      'emp_reason',
203      'employer2',
204      'emp2_position',
205      'emp2_start',
206      'emp2_end',
207      'emp2_reason',
208      'former_matric',
209    )
210PTEE_OMIT_MANAGE_FIELDS = (
211    'special_application','jamb_subjects_list',) + PTEE_OMIT_FIELDS
212PTEE_OMIT_EDIT_FIELDS = PTEE_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
213    'student_id',
214    'notice',
215    )
216
217UPDATE_OMIT_FIELDS = (
218    'firstname',
219    'middlename',
220    'lastname',
221    'sex',
222    'lga',
223    'course1',
224    )
225
226class CustomApplicantDisplayFormPage(NigeriaApplicantDisplayFormPage):
227    """A display view for applicant data.
228    """
229
230    @property
231    def form_fields(self):
232        if self.target is not None and self.target == 'trans':
233            form_fields = grok.AutoFields(ITranscriptApplicant).omit(
234                'locked', 'suspended')
235            form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
236            form_fields['perm_address'].custom_widget = BytesDisplayWidget
237            return form_fields
238        if self.target is not None and self.target == 'cert':
239            form_fields = grok.AutoFields(ICertificateRequest).omit(
240                'locked', 'suspended')
241            form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
242            form_fields['perm_address'].custom_widget = BytesDisplayWidget
243            return form_fields
244        # AAUE is using the same interface for all regular applications.
245        form_fields = grok.AutoFields(ICustomUGApplicant)
246        if self.target is not None and self.target.startswith('pg'):
247            for field in PG_OMIT_DISPLAY_FIELDS:
248                form_fields = form_fields.omit(field)
249        elif self.target is not None and self.target in ('ptee',):
250            for field in PTEE_OMIT_DISPLAY_FIELDS:
251                form_fields = form_fields.omit(field)
252        elif self.target is not None and self.target in ('ude',):
253            for field in UDE_OMIT_DISPLAY_FIELDS:
254                form_fields = form_fields.omit(field)
255        else:
256            for field in UG_OMIT_DISPLAY_FIELDS:
257                form_fields = form_fields.omit(field)
258        form_fields['perm_address'].custom_widget = BytesDisplayWidget
259        form_fields['notice'].custom_widget = BytesDisplayWidget
260        if not getattr(self.context, 'student_id'):
261            form_fields = form_fields.omit('student_id')
262        if not getattr(self.context, 'screening_score'):
263            form_fields = form_fields.omit('screening_score')
264        if not getattr(self.context, 'screening_venue') or \
265            self.context.state not in ('submitted', 'admitted', 'created'):
266            form_fields = form_fields.omit('screening_venue')
267        if not getattr(self.context, 'screening_date') or \
268            self.context.state not in ('submitted', 'admitted', 'created'):
269            form_fields = form_fields.omit('screening_date')
270        return form_fields
271
272    def getCourseAdmitted(self):
273        """Return link, title and code in html format to the certificate
274           admitted.
275        """
276        if self.layout.isApplicant():
277            return ''
278        course_admitted = self.context.course_admitted
279        if getattr(course_admitted, '__parent__',None):
280            url = self.url(course_admitted)
281            title = course_admitted.title
282            code = course_admitted.code
283            return '<a href="%s">%s - %s</a>' %(url,code,title)
284        return ''
285
286class CustomPDFActionButton(PDFActionButton):
287
288    @property
289    def target_url(self):
290        if self.context.state in ('initialized', 'started', 'paid') \
291            or self.context.special or self.view.target in ('trans', 'cert'):
292            return
293        return self.view.url(self.view.context, self.target)
294
295
296class CustomPDFApplicationSlip(NigeriaPDFApplicationSlip):
297
298    column_two_fields = ('applicant_id', 'reg_number',
299        'firstname', 'middlename', 'lastname', 'sex', 'date_of_birth')
300    #two_columns_design_fields = [
301    #    'fst_sit_fname', 'fst_sit_no', 'fst_sit_date',
302    #    'fst_sit_type', 'fst_sit_results',
303    #    'scd_sit_fname', 'scd_sit_no', 'scd_sit_date',
304    #    'scd_sit_type', 'scd_sit_results']
305
306    def _getCourseAdmittedLink(self, view):
307        return None
308
309    def _getDeptAndFaculty(self):
310        return [None, None]
311
312    @property
313    def note(self):
314        note = getattr(self.context.__parent__, 'application_slip_notice', None)
315        if note:
316            return '<br /><br />' + note
317        if self.context.sex == 'm':
318            pronoun = 'he'
319        else:
320            pronoun = 'she'
321        return '''
322The applicant has acknowledged that, if discovered at any time that %s does not possess
323any of the qualifications which %s claims %s has obtained, %s will be expelled from the
324University not be re-admitted for the same or any other programme, even if %s has
325upgraded previous qualifications or possess additional qualifications.
326
327''' % (
328    pronoun, pronoun, pronoun, pronoun, pronoun)
329
330    @property
331    def form_fields(self):
332        # AAUE is using the same interface for all regular applications.
333        form_fields = grok.AutoFields(ICustomUGApplicant)
334        if self.target is not None and self.target.startswith('pg'):
335            for field in PG_OMIT_PDF_FIELDS:
336                form_fields = form_fields.omit(field)
337        elif self.target is not None and self.target in ('ptee',):
338            for field in PTEE_OMIT_PDF_FIELDS:
339                form_fields = form_fields.omit(field)
340        elif self.target is not None and self.target in ('ude',):
341            for field in UDE_OMIT_PDF_FIELDS:
342                form_fields = form_fields.omit(field)
343        else:
344            for field in UG_OMIT_PDF_FIELDS:
345                form_fields = form_fields.omit(field)
346        if not getattr(self.context, 'student_id'):
347            form_fields = form_fields.omit('student_id')
348        if not getattr(self.context, 'screening_score'):
349            form_fields = form_fields.omit('screening_score')
350        if not getattr(self.context, 'screening_venue'):
351            form_fields = form_fields.omit('screening_venue')
352        if not getattr(self.context, 'screening_date'):
353            form_fields = form_fields.omit('screening_date')
354        return form_fields
355
356class CustomApplicantManageFormPage(NigeriaApplicantManageFormPage):
357    """A full edit view for applicant data.
358    """
359
360    @property
361    def form_fields(self):
362        if self.target is not None and self.target == 'trans':
363            form_fields = grok.AutoFields(ITranscriptApplicant)
364            form_fields['applicant_id'].for_display = True
365            return form_fields
366        if self.target is not None and self.target == 'cert':
367            form_fields = grok.AutoFields(ICertificateRequest)
368            form_fields['applicant_id'].for_display = True
369            return form_fields
370        # AAUE is using the same interface for all regular applications.
371        form_fields = grok.AutoFields(ICustomUGApplicant)
372        if self.target is not None and self.target.startswith('pg'):
373            for field in PG_OMIT_MANAGE_FIELDS:
374                form_fields = form_fields.omit(field)
375        elif self.target is not None and self.target in ('ptee',):
376            for field in PTEE_OMIT_MANAGE_FIELDS:
377                form_fields = form_fields.omit(field)
378        elif self.target is not None and self.target in ('ude',):
379            for field in UDE_OMIT_MANAGE_FIELDS:
380                form_fields = form_fields.omit(field)
381        else:
382            for field in UG_OMIT_MANAGE_FIELDS:
383                form_fields = form_fields.omit(field)
384        form_fields['student_id'].for_display = True
385        form_fields['applicant_id'].for_display = True
386        return form_fields
387
388class CustomApplicantEditFormPage(NigeriaApplicantEditFormPage):
389    """An applicant-centered edit view for applicant data.
390    """
391
392    def unremovable(self, ticket):
393        return True
394
395    # AAUE applicants never see the 'Remove Selected Tickets' button.
396    @property
397    def display_actions(self):
398        # If the form is unlocked, applicants are allowed to save the form
399        # and remove unused tickets.
400        actions = [[_('Save')], []]
401        # Only in state started they can also add tickets.
402        if self.context.state == STARTED:
403            actions = [[_('Save')],
404                [_('Add online payment ticket')]]
405        # In state paid, they can submit the data and further add tickets
406        # if the application is special.
407        elif self.context.special and self.context.state == PAID:
408            actions = [[_('Save'), _('Finally Submit')],
409                [_('Add online payment ticket')]]
410        elif self.context.state == PAID:
411            actions = [[_('Save'), _('Finally Submit')], []]
412        return actions
413
414    @property
415    def form_fields(self):
416        if self.target is not None and self.target == 'trans':
417            form_fields = grok.AutoFields(ITranscriptApplicant).omit(
418                'locked', 'suspended')
419            form_fields['applicant_id'].for_display = True
420            form_fields['reg_number'].for_display = True
421            return form_fields
422        if self.target is not None and self.target == 'cert':
423            form_fields = grok.AutoFields(ICertificateRequest).omit(
424                'locked', 'suspended')
425            form_fields['applicant_id'].for_display = True
426            form_fields['reg_number'].for_display = True
427            # Additional omissions
428            if self.context.__parent__.code == 'cert5':
429                for field in ('firstname', 'middlename', 'lastname'):
430                    form_fields[field].for_display = True
431            return form_fields
432        # AAUE is using the same interface for all regular applications.
433        form_fields = grok.AutoFields(ICustomUGApplicantEdit)
434        if self.target is not None and self.target.startswith('pg'):
435            for field in PG_OMIT_EDIT_FIELDS:
436                form_fields = form_fields.omit(field)
437        elif self.target is not None and self.target in ('ptee',):
438            for field in PTEE_OMIT_EDIT_FIELDS:
439                form_fields = form_fields.omit(field)
440        elif self.target is not None and self.target in ('ude',):
441            for field in UDE_OMIT_EDIT_FIELDS:
442                form_fields = form_fields.omit(field)
443        else:
444            for field in UG_OMIT_EDIT_FIELDS:
445                form_fields = form_fields.omit(field)
446        # Additional omissions
447        if self.target is not None and self.target in ('ude', 'utme'):
448            for field in UPDATE_OMIT_FIELDS:
449                form_fields[field].for_display = True
450        form_fields['applicant_id'].for_display = True
451        form_fields['reg_number'].for_display = True
452        return form_fields
453
454class CustomApplicantRegistrationPage(NigeriaApplicantRegistrationPage):
455    """Captcha'd registration page for applicants.
456    """
457
458    @property
459    def form_fields(self):
460        form_fields = None
461        if self.context.mode == 'update':
462            form_fields = grok.AutoFields(IApplicantRegisterUpdate).select(
463                'lastname','reg_number','email')
464            target = getattr(self.context, 'prefix', None)
465            if target in ('trans', 'cert'):
466                form_fields.get('reg_number').field.title = u'Matriculation Number'
467        else: #if self.context.mode == 'create':
468            form_fields = grok.AutoFields(ICustomUGApplicantEdit).select(
469                'firstname', 'middlename', 'lastname', 'email', 'phone')
470        return form_fields
471
472    def _redirect(self, email, password, applicant_id):
473        # Forward email and credentials to landing page.
474        self.redirect(self.url(self.context, 'registration_complete',
475            data = dict(email=email, password=password,
476            applicant_id=applicant_id)))
477        return
478
479    @property
480    def _postfix(self):
481        """Alumni records have to be imported into several containers.
482        Therefore a string must be added to their registration number
483        to make it unique.
484        """
485        if self.context.prefix in ('trans', 'cert'):
486            return self.context.code
487        return ''
488
489class CustomExportPDFPaymentSlipPage(NigeriaExportPDFPaymentSlipPage):
490
491    @property
492    def payment_slip_download_warning(self):
493        return ''
494
495class CustomApplicantCheckStatusPage(ApplicantCheckStatusPage):
496    """Captcha'd status checking page for applicants.
497    """
498    grok.template('applicantcheckstatus')
499
500class ScreeningInvitationActionButton(ManageActionButton):
501    grok.order(8) # This button should always be the last one.
502    grok.context(ICustomApplicant)
503    grok.view(CustomApplicantDisplayFormPage)
504    grok.require('waeup.viewApplication')
505    icon = 'actionicon_pdf.png'
506    text = _('Download screening invitation letter')
507    target = 'screening_invitation.pdf'
508
509    @property
510    def target_url(self):
511        if not self.context.screening_date or not self.context.state in (
512            'submitted', 'admitted', 'created'):
513            return ''
514        return self.view.url(self.view.context, self.target)
515
516class ExportScreeningInvitationLetter(UtilityView, grok.View):
517    """Deliver a slip with only screening data.
518    This form page is available only in AAUE.
519    """
520    grok.context(ICustomApplicant)
521    grok.name('screening_invitation.pdf')
522    grok.require('waeup.viewApplication')
523    prefix = 'form'
524
525    label = u'Screening Invitation Letter'
526
527    form_fields = []
528
529    @property
530    def note(self):
531        if self.context.screening_date:
532            year = self.context.__parent__.year
533            session = '%s/%s' % (year, year + 1)
534            sdate = self.context.screening_date
535            stime = ''
536            if '@' in self.context.screening_date:
537                sdate = self.context.screening_date.split('@')[0].strip()
538                stime = self.context.screening_date.split('@')[1].strip()
539            return """
540<br /><br /><br /><br /><font size='12'>
541Dear %s,
542<br /><br />
543You are invited to the Ambrose Alli University %s Admissions Screening Exercise.
544<br /><br />
545<strong>Date: %s
546<br /><br />
547Time: %s
548<br /><br />
549Venue: %s
550</strong>
551<br /><br />
552Please bring this letter of invitation and the downloaded application form along with you on your screening date.
553<br /><br />
554You are expected to be available 30 minutes before the commencement of your Screening.
555</font>
556
557""" % (
558       self.context.display_fullname,
559       session,
560       sdate,
561       stime,
562       self.context.screening_venue)
563        return
564
565    @property
566    def title(self):
567        return None
568
569    def update(self):
570        if not self.context.screening_date or not self.context.state in (
571            'submitted', 'admitted', 'created'):
572            self.flash(_('Forbidden'), type="warning")
573            self.redirect(self.url(self.context))
574
575    def render(self):
576        applicantview = ApplicantBaseDisplayFormPage(self.context, self.request)
577        students_utils = getUtility(IStudentsUtils)
578        return students_utils.renderPDF(self,'screening_data.pdf',
579            self.context, applicantview, note=self.note)
Note: See TracBrowser for help on using the repository browser.