source: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/applicants/browser.py @ 16599

Last change on this file since 16599 was 16566, checked in by Henrik Bettermann, 3 years ago

Finetune requirements for submission.

  • Property svn:keywords set to Id
File size: 16.9 KB
RevLine 
[10765]1## $Id: browser.py 16566 2021-08-12 06:40:29Z 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
[15878]21import os
[16075]22from zope.component import getUtility, queryUtility
23from zope.catalog.interfaces import ICatalog
[15807]24from zope.formlib.textwidgets import BytesDisplayWidget
[15878]25from waeup.kofa.interfaces import (
26    IExtFileStore, IFileStoreNameChooser)
27from waeup.kofa.utils.helpers import string_from_bytes, file_size, now
[10765]28from waeup.kofa.applicants.browser import (
[16062]29    ApplicantRegistrationPage, ApplicantsContainerPage, AdditionalFile,
30    RefereeReportAddFormPage, ExportPDFReportSlipPage, ExportPDFReportSlipPage2,
[16328]31    RefereeReportDisplayFormPage,
[16559]32    ApplicantsContainerManageFormPage,
33    ApplicantAddFormPage)
[15809]34from waeup.kofa.applicants.interfaces import (
[16070]35    ISpecialApplicant, IApplicantsContainer, AppCatCertificateSource)
[10765]36from kofacustom.nigeria.applicants.browser import (
37    NigeriaApplicantDisplayFormPage,
[15807]38    NigeriaApplicantManageFormPage,
39    NigeriaApplicantEditFormPage,
[10765]40    NigeriaPDFApplicationSlip)
[15809]41from waeup.kofa.widgets.datewidget import (
42    FriendlyDateDisplayWidget,
43    FriendlyDatetimeDisplayWidget)
[15807]44from kofacustom.nigeria.applicants.interfaces import (
[15884]45    OMIT_DISPLAY_FIELDS,
46    #UG_OMIT_DISPLAY_FIELDS,
47    #UG_OMIT_PDF_FIELDS,
48    #UG_OMIT_MANAGE_FIELDS,
49    #UG_OMIT_EDIT_FIELDS,
[16049]50    #PG_OMIT_DISPLAY_FIELDS,
51    #PG_OMIT_PDF_FIELDS,
52    #PG_OMIT_MANAGE_FIELDS,
53    #PG_OMIT_EDIT_FIELDS,
[15807]54    )
55from kofacustom.iuokada.applicants.interfaces import (
[15878]56    ICustomPGApplicant, ICustomUGApplicant, ICustomApplicant,
[15807]57    ICustomPGApplicantEdit, ICustomUGApplicantEdit,
[16142]58    ICustomApplicantOnlinePayment, ICustomApplicantRefereeReport,
[16281]59    ITranscriptApplicant, ICustomApplicantRegisterUpdate
[15807]60    )
[15563]61from kofacustom.iuokada.interfaces import MessageFactory as _
[10765]62
[15878]63MAX_FILE_UPLOAD_SIZE = 1024 * 500
64
[15884]65# UG students are all undergraduate students.
66UG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
67    #'jamb_subjects_list',
68    'programme_type',)
69UG_OMIT_PDF_FIELDS = UG_OMIT_DISPLAY_FIELDS + ('phone',)
70UG_OMIT_MANAGE_FIELDS = (
71    'special_application',
72    #'jamb_subjects_list',
[16075]73    'programme_type',
74    'course1',
75    'course2',)
[15884]76UG_OMIT_EDIT_FIELDS = UG_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
77    'student_id',
78    'notice',
79    'screening_score',
80    'screening_venue',
81    'screening_date',
82    #'jamb_age',
83    #'jamb_subjects',
84    #'jamb_score',
85    #'jamb_reg_number',
[16075]86    'aggregate',
87    )
[15884]88
[16559]89JUPEB_OMIT_FIELDS = (
90    'jamb_age',
91    'jamb_subjects',
92    'jamb_score',
93    'jamb_reg_number',
94    'jamb_subjects_list',
95    'jamb_fname',
96    )
97
[16049]98# PG has its own interface
[16053]99PG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
100    'employer',
101    'emp_position',
102    'emp_start',
103    'emp_end',
104    'emp_reason',
105    'employer2',
106    'emp2_position',
107    'emp2_start',
108    'emp2_end',
109    'emp2_reason',
110    )
[16049]111PG_OMIT_PDF_FIELDS = PG_OMIT_DISPLAY_FIELDS + ('phone',)
112PG_OMIT_MANAGE_FIELDS = (
113    'special_application',
114    'employer',
115    'emp_position',
116    'emp_start',
117    'emp_end',
118    'emp_reason',
119    'employer2',
120    'emp2_position',
121    'emp2_start',
122    'emp2_end',
123    'emp2_reason',
[16075]124    'course1',
125    'course2',
[16049]126    )
127PG_OMIT_EDIT_FIELDS = PG_OMIT_MANAGE_FIELDS + PG_OMIT_DISPLAY_FIELDS + (
[16053]128    'student_id',
129    'notice',
130    'screening_score',
131    'screening_venue',
[16049]132    'screening_date',)
133
[16209]134TRANS_OMIT_FIELDS = ('suspended', 'applicant_id',)
[16142]135
136TRANS_SHORT_OMIT_FIELDS = TRANS_OMIT_FIELDS + (
[16165]137    #'date_of_birth',
[16142]138    'sex',
139    'nationality',
[16165]140    #'entry_mode',
141    #'entry_session',
[16142]142    'end_session',
[16165]143    #'course_studied',
144    #'course_changed',
145    #'change_level',
[16142]146    )
147
[15809]148class CustomApplicantsContainerPage(ApplicantsContainerPage):
149    """The standard view for regular applicant containers.
150    """
151
152    @property
153    def form_fields(self):
154        form_fields = grok.AutoFields(IApplicantsContainer).omit(
155            'title', 'description')
156        if self.request.principal.id == 'zope.anybody':
157            form_fields = form_fields.omit(
158                'code', 'prefix', 'year', 'mode', 'hidden',
159                'strict_deadline', 'application_category',
[15883]160                'application_slip_notice',
161                'application_fee', 'with_picture',
162                'startdate', 'enddate')
[15809]163        return form_fields
164
[16328]165class CustomApplicantsContainerManageFormPage(ApplicantsContainerManageFormPage):
166
167    max_applicants = 3000
168
[15793]169class CustomApplicantDisplayFormPage(NigeriaApplicantDisplayFormPage):
170    """A display view for applicant data.
171    """
[15807]172
[15793]173    @property
174    def form_fields(self):
[16165]175        if self.target is not None and self.target == 'tscf':
[16142]176            form_fields = grok.AutoFields(ITranscriptApplicant)
177            for field in TRANS_OMIT_FIELDS:
178                form_fields = form_fields.omit(field)
179            form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
[16165]180            #form_fields['perm_address'].custom_widget = BytesDisplayWidget
[16142]181            return form_fields
[16165]182        if self.target is not None and self.target == 'tscs':
[16142]183            form_fields = grok.AutoFields(ITranscriptApplicant)
184            for field in TRANS_SHORT_OMIT_FIELDS:
185                form_fields = form_fields.omit(field)
186            form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
[16165]187            #form_fields['perm_address'].custom_widget = BytesDisplayWidget
[16142]188            return form_fields
[15807]189        if self.target is not None and self.target.startswith('pg'):
190            form_fields = grok.AutoFields(ICustomPGApplicant)
191            for field in PG_OMIT_DISPLAY_FIELDS:
192                form_fields = form_fields.omit(field)
[15793]193        else:
[15807]194            form_fields = grok.AutoFields(ICustomUGApplicant)
195            for field in UG_OMIT_DISPLAY_FIELDS:
196                form_fields = form_fields.omit(field)
[16559]197        if self.target is not None and self.target == 'pre':
198            for field in JUPEB_OMIT_FIELDS:
199                form_fields = form_fields.omit(field)
[15807]200        #form_fields['perm_address'].custom_widget = BytesDisplayWidget
201        form_fields['notice'].custom_widget = BytesDisplayWidget
202        if not getattr(self.context, 'student_id'):
203            form_fields = form_fields.omit('student_id')
204        if not getattr(self.context, 'screening_score'):
205            form_fields = form_fields.omit('screening_score')
206        if not getattr(self.context, 'screening_venue') or self._not_paid():
207            form_fields = form_fields.omit('screening_venue')
208        if not getattr(self.context, 'screening_date') or self._not_paid():
209            form_fields = form_fields.omit('screening_date')
[15793]210        return form_fields
211
[16165]212def getCerts(view, coursex):
213    yield(dict(code='', title='--', selected=''))
214    appcatcertificatesource = AppCatCertificateSource().factory
215    for cert in appcatcertificatesource.getValues(view.context):
216        selected = ''
217        course = getattr(view.context, coursex)
218        if course is not None and course.code == cert.code:
219            selected = 'selected'
220        title = appcatcertificatesource.getTitle(view.context, cert)
221        yield(dict(code=cert.code, title=title, selected=selected))
222
[16220]223def saveCourses(view):
[16165]224    """In custom packages we needed to customize the certificate
225    select widget. We just save course1 and course2 if these customized
226    fields appear in the form.
227    """
[16220]228    changed_courses = []
[16165]229    form = view.request.form
230    course1 = form.get('custom.course1', None)
[16220]231    if not course1:
232        return 'Please select your 1st Choice Course of Study.', None
233    cat = queryUtility(ICatalog, name='certificates_catalog')
234    results = list(
235        cat.searchResults(code=(course1, course1)))
236    new_course1 = results[0]
237    old_course1 = view.context.course1
238    if old_course1 != new_course1:
239        view.context.course1 = new_course1
240        changed_courses.append('course1')
241    new_course2 = None
242    old_course2 = view.context.course2
[16165]243    course2 = form.get('custom.course2', None)
244    if course2:
245        results = list(
246            cat.searchResults(code=(course2, course2)))
[16220]247        new_course2 = results[0]
248    if old_course2 != new_course2:
249        view.context.course2 = new_course2
250        changed_courses.append('course2')
251    return None, changed_courses
[16165]252
253def display_fileupload(view, filename):
254    if view.target.startswith('tsc'):
255        return False
256    if filename[1] == 'res_stat.pdf':
257        if view.context.subtype != 'transfer':
258            return False
259    if filename[1] == 'jamb.pdf' \
260        and view.target is not None \
261        and view.target.startswith('pg'):
262        return False
263    if filename[1] == 'nysc.pdf' \
264        and view.target is not None \
265        and not view.target.startswith('pg'):
266        return False
267    return True
268
[15807]269class CustomApplicantManageFormPage(NigeriaApplicantManageFormPage):
270    """A full edit view for applicant data.
271    """
272
[16075]273    def getCerts(self, coursex):
[16165]274        return getCerts(self, coursex)
[16070]275
[16220]276    def saveCourses(self):
277        return saveCourses(self)
[16075]278
[16165]279    def display_fileupload(self, filename):
280        return display_fileupload(self, filename)
281
[16070]282    @property
[16051]283    def display_refereereports(self):
284        if self.context.refereereports:
285            return True
286        return False
287
288    @property
[15807]289    def form_fields(self):
[16165]290        self.course_selector = False
291        if self.target is not None and self.target == 'tscf':
[16142]292            form_fields = grok.AutoFields(ITranscriptApplicant)
293            for field in TRANS_OMIT_FIELDS:
294                form_fields = form_fields.omit(field)
295            return form_fields
[16165]296        if self.target is not None and self.target == 'tscs':
[16142]297            form_fields = grok.AutoFields(ITranscriptApplicant)
298            for field in TRANS_SHORT_OMIT_FIELDS:
299                form_fields = form_fields.omit(field)
300            return form_fields
[16165]301        self.course_selector = True
[15807]302        if self.target is not None and self.target.startswith('pg'):
303            form_fields = grok.AutoFields(ICustomPGApplicant)
304            for field in PG_OMIT_MANAGE_FIELDS:
305                form_fields = form_fields.omit(field)
306        else:
307            form_fields = grok.AutoFields(ICustomUGApplicant)
308            for field in UG_OMIT_MANAGE_FIELDS:
309                form_fields = form_fields.omit(field)
[16559]310        if self.target is not None and self.target == 'pre':
311            for field in JUPEB_OMIT_FIELDS:
312                form_fields = form_fields.omit(field)
[15807]313        form_fields['student_id'].for_display = True
314        form_fields['applicant_id'].for_display = True
315        return form_fields
316
317class CustomApplicantEditFormPage(NigeriaApplicantEditFormPage):
318    """An applicant-centered edit view for applicant data.
319    """
320
[16075]321    def getCerts(self, coursex):
[16165]322        return getCerts(self, coursex)
[16070]323
[16075]324    def saveCourses(self):
[16165]325        return saveCourses(self)
[16075]326
[15947]327    def display_fileupload(self, filename):
[16165]328        return display_fileupload(self, filename)
[15947]329
[15878]330    def dataNotComplete(self, data):
331        store = getUtility(IExtFileStore)
[16566]332        if self.context.subtype \
333            and self.context.subtype not in ('transfer', 'de') \
[16565]334            and (not self.context.jamb_fname
335                 or not self.context.jamb_reg_number):
336            return _('JAMB fields must be filled.')
[15878]337        if self.context.__parent__.with_picture:
338            store = getUtility(IExtFileStore)
339            if not store.getFileByContext(self.context, attr=u'passport.jpg'):
340                return _('No passport picture uploaded.')
[16077]341        if self.context.subtype == 'transfer' \
342            and self.context.__parent__.code!= 'ug2020' \
343            and not store.getFileByContext(self.context, attr=u'res_stat.pdf'):
[15878]344            return _('No statement of result pdf file uploaded.')
345        return False
346
[15807]347    @property
348    def form_fields(self):
[16165]349        self.course_selector = False
350        if self.target is not None and self.target == 'tscf':
[16142]351            form_fields = grok.AutoFields(ITranscriptApplicant)
352            for field in TRANS_OMIT_FIELDS:
353                form_fields = form_fields.omit(field)
[16209]354                form_fields = form_fields.omit('locked')
[16142]355            return form_fields
[16165]356        if self.target is not None and self.target == 'tscs':
[16142]357            form_fields = grok.AutoFields(ITranscriptApplicant)
358            for field in TRANS_SHORT_OMIT_FIELDS:
359                form_fields = form_fields.omit(field)
[16209]360                form_fields = form_fields.omit('locked')
[16142]361            return form_fields
[16165]362        self.course_selector = True
[15807]363        if self.target is not None and self.target.startswith('pg'):
364            form_fields = grok.AutoFields(ICustomPGApplicantEdit)
365            for field in PG_OMIT_EDIT_FIELDS:
366                form_fields = form_fields.omit(field)
367        else:
368            form_fields = grok.AutoFields(ICustomUGApplicantEdit)
369            for field in UG_OMIT_EDIT_FIELDS:
370                form_fields = form_fields.omit(field)
[16559]371        if self.target is not None and self.target == 'pre':
372            for field in JUPEB_OMIT_FIELDS:
373                form_fields = form_fields.omit(field)
[15807]374        form_fields['applicant_id'].for_display = True
375        form_fields['reg_number'].for_display = True
376        return form_fields
377
378class CustomPDFApplicationSlip(NigeriaPDFApplicationSlip):
379
380    @property
381    def form_fields(self):
382        if self.target is not None and self.target.startswith('pg'):
383            form_fields = grok.AutoFields(ICustomPGApplicant)
384            for field in PG_OMIT_PDF_FIELDS:
385                form_fields = form_fields.omit(field)
386        else:
387            form_fields = grok.AutoFields(ICustomUGApplicant)
388            for field in UG_OMIT_PDF_FIELDS:
389                form_fields = form_fields.omit(field)
390        if not getattr(self.context, 'student_id'):
391            form_fields = form_fields.omit('student_id')
392        if not getattr(self.context, 'screening_score'):
393            form_fields = form_fields.omit('screening_score')
394        if not getattr(self.context, 'screening_venue'):
395            form_fields = form_fields.omit('screening_venue')
396        if not getattr(self.context, 'screening_date'):
397            form_fields = form_fields.omit('screening_date')
398        return form_fields
399
[16281]400class CustomApplicantRegistrationPage(ApplicantRegistrationPage):
401    """Captcha'd registration page for applicants.
402    """
403    @property
404    def form_fields(self):
405        form_fields = None
406        if self.context.mode == 'update':
407            form_fields = grok.AutoFields(ICustomApplicantRegisterUpdate).select(
408                'lastname','reg_number','email')
409        else: #if self.context.mode == 'create':
410            form_fields = grok.AutoFields(ICustomUGApplicant).select(
411                'firstname', 'middlename', 'lastname', 'email', 'phone')
412        return form_fields
413
[16559]414class CustomApplicantAddFormPage(ApplicantAddFormPage):
415    """Add-form to add an applicant.
416    """
417    form_fields = grok.AutoFields(ICustomApplicant).select(
418        'firstname', 'middlename', 'lastname',
419        'email', 'phone')
420
[16062]421class RefereeReportAddFormPage(RefereeReportAddFormPage):
422    """Add-form to add an referee report. This form
423    is protected by a mandate.
424    """
425    form_fields = grok.AutoFields(
426        ICustomApplicantRefereeReport).omit('creation_date')
427
428class CustomRefereeReportDisplayFormPage(RefereeReportDisplayFormPage):
429    """A display view for referee reports.
430    """
431    form_fields = grok.AutoFields(ICustomApplicantRefereeReport)
432    form_fields[
433        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
434
435
436class CustomExportPDFReportSlipPage(ExportPDFReportSlipPage):
437    form_fields = grok.AutoFields(ICustomApplicantRefereeReport)
438    form_fields[
439        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
440
441class CustomExportPDFReportSlipPage2(ExportPDFReportSlipPage2):
442    form_fields = grok.AutoFields(ICustomApplicantRefereeReport)
443    form_fields[
444        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
445
[15947]446class ResultStatement(AdditionalFile):
[16546]447    grok.name('res_stat')
[15878]448
[15947]449class JAMBResult(AdditionalFile):
[16546]450    grok.name('jamb')
[16014]451
452class FirstSitting(AdditionalFile):
[16546]453    grok.name('fst_sit_scan')
[16014]454
455class SecondSitting(AdditionalFile):
[16546]456    grok.name('scd_sit_scan')
[16014]457
458class HighQual(AdditionalFile):
[16546]459    grok.name('hq_scan')
[16017]460
461class AdvancedLevelResult(AdditionalFile):
[16546]462    grok.name('alr_scan')
[16052]463
464class NYSCCertificate(AdditionalFile):
[16546]465    grok.name('nysc')
[16501]466
467class PaymentReceipts(AdditionalFile):
[16546]468    grok.name('rmp')
Note: See TracBrowser for help on using the repository browser.