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

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

Do it right.

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