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

Last change on this file since 17549 was 17159, checked in by Henrik Bettermann, 2 years ago

Extend max_applicants.

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