source: main/kofacustom.dspg/trunk/src/kofacustom/dspg/applicants/browser.py @ 16728

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

Change carryover_courses_1 and carryover_courses_2 fields.

  • Property svn:keywords set to Id
File size: 16.6 KB
RevLine 
[10765]1## $Id: browser.py 16726 2021-11-25 22:26:32Z 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
[15498]21from zope.component import getUtility, queryUtility
[14721]22from zope.i18n import translate
[14807]23from hurry.workflow.interfaces import IWorkflowState
[14721]24from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
25from zope.formlib.textwidgets import BytesDisplayWidget
[14732]26from waeup.kofa.interfaces import IExtFileStore, IKofaUtils
[15498]27from waeup.kofa.browser.pages import doll_up
[14721]28from waeup.kofa.applicants.interfaces import (
[15498]29    IApplicant, IApplicantEdit,
30    IApplicantsContainer,)
[14721]31from waeup.kofa.applicants.browser import (ApplicantDisplayFormPage,
32    ApplicantManageFormPage, ApplicantEditFormPage,
[15498]33    ApplicantsContainerPage, ApplicationFeePaymentAddPage,
34    ExportJobContainerOverview,
35    ExportJobContainerJobStart,
[15580]36    ExportJobContainerDownload,
37    ApplicantBaseDisplayFormPage)
[15498]38from waeup.kofa.browser.viewlets import ManageActionButton
[14721]39from waeup.kofa.applicants.viewlets import (
40    PaymentReceiptActionButton, PDFActionButton)
41from waeup.kofa.applicants.pdf import PDFApplicationSlip
[14807]42from waeup.kofa.applicants.workflow import ADMITTED, PAID, STARTED
[15580]43from waeup.kofa.students.interfaces import IStudentsUtils
[14721]44from kofacustom.nigeria.applicants.interfaces import (
45    UG_OMIT_DISPLAY_FIELDS,
46    UG_OMIT_PDF_FIELDS,
47    UG_OMIT_MANAGE_FIELDS,
48    UG_OMIT_EDIT_FIELDS
49    )
[15580]50from kofacustom.nigeria.applicants.browser import (
51    NigeriaExportPDFPaymentSlipPage)
[14721]52from kofacustom.dspg.applicants.interfaces import (
53    ICustomUGApplicant, ICustomUGApplicantEdit,
[14865]54    ICustomSpecialApplicant,
[15580]55    ICustomApplicantOnlinePayment,
56    ICustomApplicant,
[14721]57    ND_OMIT_DISPLAY_FIELDS,
58    ND_OMIT_PDF_FIELDS,
59    ND_OMIT_MANAGE_FIELDS,
60    ND_OMIT_EDIT_FIELDS
61    )
[10765]62
[14732]63from kofacustom.dspg.interfaces import MessageFactory as _
64
[14721]65UG_OMIT_EDIT_FIELDS = [
66    value for value in UG_OMIT_EDIT_FIELDS
67        if not value in ('jamb_subjects', 'jamb_score', 'jamb_reg_number')]
[10765]68
[14721]69PRE_OMIT_EDIT_FIELDS = UG_OMIT_EDIT_FIELDS + [
70    'firstname',
71    'middlename',
72    'lastname',
73    #'sex',
74    'jamb_score'
75    ]
76
[15498]77##### Bursary exports
78
79class BursaryExportPaymentsActionButton(ManageActionButton):
80    """ 'Export payment data' button for faculties.
81    """
82    grok.context(IApplicantsContainer)
83    grok.view(ApplicantsContainerPage)
84    grok.require('waeup.exportBursaryData')
85    icon = 'actionicon_down.png'
86    text = _('Export payment data')
87    grok.order(4)
88
[15518]89    @property
90    def target_url(self):
91        return self.view.url(self.view.context) + '/exports/bursary.html'
92
[15498]93class BursaryExportJobContainerOverview(ExportJobContainerOverview):
94    """Page that lists active applicant data export jobs and provides links
95    to discard or download CSV files.
96    """
97    grok.require('waeup.exportBursaryData')
[15518]98    grok.name('bursary.html')
[15498]99
100    def update(self, CREATE=None, DISCARD=None, job_id=None):
101        if CREATE:
102            self.redirect(self.url('@@start_bursary_export'))
103            return
104        if DISCARD and job_id:
105            entry = self.context.entry_from_job_id(job_id)
106            self.context.delete_export_entry(entry)
107            ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
108            self.context.logger.info(
109                '%s - discarded: job_id=%s' % (ob_class, job_id))
110            self.flash(_('Discarded export') + ' %s' % job_id)
111        self.entries = doll_up(self, user=self.request.principal.id)
112        return
113
114class  BursaryExportJobContainerJobStart(ExportJobContainerJobStart):
115    """View that starts export job.
116    """
117    grok.require('waeup.exportBursaryData')
118    grok.name('start_bursary_export')
119
120    def update(self):
121        utils = queryUtility(IKofaUtils)
122        if not utils.expensive_actions_allowed():
123            self.flash(_(
124                "Currently, exporters cannot be started due to high "
125                "system load. Please try again later."), type='danger')
126            self.entries = doll_up(self, user=None)
127            return
128
129        ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
130        container_code = self.context.__parent__.code
131        # Start payments exporter
132        exporter = 'applicantpayments'
133        job_id = self.context.start_export_job(exporter,
134                                      self.request.principal.id,
135                                      container=container_code)
136        self.context.logger.info(
137            '%s - exported: %s (%s), job_id=%s'
138            % (ob_class, exporter, container_code, job_id))
139
140        self.flash(_('Exports started.'))
[15518]141        self.redirect(self.url(self.context, 'bursary.html'))
[15498]142        return
143
144    def render(self):
145        return
146
147class BursaryExportJobContainerDownload(ExportJobContainerDownload):
148    """Page that downloads a students export csv file.
149
150    """
151    grok.require('waeup.exportBursaryData')
152
[14721]153class CustomApplicantsContainerPage(ApplicantsContainerPage):
154    """The standard view for regular applicant containers.
155    """
156
157    @property
158    def form_fields(self):
159        form_fields = super(CustomApplicantsContainerPage, self).form_fields
160        if self.request.principal.id == 'zope.anybody':
161            return form_fields.omit('application_fee')
162        return form_fields
163
164class CustomApplicantDisplayFormPage(ApplicantDisplayFormPage):
165    """A display view for applicant data.
166    """
167
168    @property
169    def form_fields(self):
170        if self.context.special:
[14865]171            return grok.AutoFields(ICustomSpecialApplicant)
[16026]172        if self.target in ('conv', 'hndfincl', 'ndfincl'):
[15576]173            form_fields = grok.AutoFields(ICustomSpecialApplicant)
174            form_fields = form_fields.omit(
[15592]175                'special_application',
176                'carryover_courses_1',
177                'carryover_courses_2',
[15576]178                'locked', 'suspended')
179            return form_fields
[14721]180        form_fields = grok.AutoFields(ICustomUGApplicant)
181        if self.context.is_nd:
182            for field in ND_OMIT_DISPLAY_FIELDS:
183                form_fields = form_fields.omit(field)
184        else:
185            form_fields = grok.AutoFields(ICustomUGApplicant)
186            for field in UG_OMIT_DISPLAY_FIELDS:
187                form_fields = form_fields.omit(field)
188        form_fields['notice'].custom_widget = BytesDisplayWidget
189        form_fields['jamb_subjects'].custom_widget = BytesDisplayWidget
190        if not getattr(self.context, 'student_id'):
191            form_fields = form_fields.omit('student_id')
192        if not getattr(self.context, 'screening_score'):
193            form_fields = form_fields.omit('screening_score')
194        if not getattr(self.context, 'screening_venue'):
195            form_fields = form_fields.omit('screening_venue')
196        if not getattr(self.context, 'screening_date'):
197            form_fields = form_fields.omit('screening_date')
198        return form_fields
199
200class CustomPDFApplicationSlip(PDFApplicationSlip):
201
202    def _reduced_slip(self):
203        return getattr(self.context, 'result_uploaded', False)
204
205    @property
206    def note(self):
[15588]207        if self.context.special:
[15592]208            return '''<br /><br />
209Head of Department Signature:
210'''
[14721]211        note = getattr(self.context.__parent__, 'application_slip_notice', None)
212        if note:
213            return '<br /><br />' + note
214        pronoun = 'S/he'
215        if self.context.sex == 'm':
216            pronoun = 'He'
217        else:
218            pronoun = 'She'
219        return '''<br /><br />
220The applicant has declared that:
221
222a) %s is not a member of any secret cult and will not join any.
223b) %s will not engage in any cult activities.
224c) %s will not be involved in any acts of terrorism, rape, robbery, fighting, illegal gathering and
225any activities that could disrupt peace on campus.
226d) %s does not have and will not acquire any form of weapon, fire arms, gun knife or any weapon
227that can cause damage to life and property.
228e) %s will strive to be worthy in character and learning at all times.
229
230The applicant has acknowledged that offences will automatically lead to the expulsion from the
231Polytechnic and also be dealt with in accordance with the law of the land.
232
233The applicant promises to abide by all the Rules and Regulations of the Polytechnic if offered
234admission.
235''' % (
236    pronoun, pronoun, pronoun, pronoun, pronoun)
237
238    @property
239    def form_fields(self):
[16726]240        if self.context.special:
241            return grok.AutoFields(ICustomSpecialApplicant)
242        if self.target in ('conv', 'hndfincl', 'ndfincl'):
[15576]243            form_fields = grok.AutoFields(ICustomSpecialApplicant)
244            form_fields = form_fields.omit(
[15588]245                'special_application',
246                'locked', 'suspended', 'applicant_id')
[15592]247            if not self.context.carryover_courses_1:
248                form_fields = form_fields.omit('carryover_courses_1')
249            if not self.context.carryover_courses_2:
250                form_fields = form_fields.omit('carryover_courses_2')
[15576]251            return form_fields
[14721]252        form_fields = grok.AutoFields(ICustomUGApplicant)
253        if self.context.is_nd:
254            for field in ND_OMIT_PDF_FIELDS:
255                form_fields = form_fields.omit(field)
256        else:
257            form_fields = grok.AutoFields(ICustomUGApplicant)
258            for field in UG_OMIT_PDF_FIELDS:
259                form_fields = form_fields.omit(field)
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'):
265            form_fields = form_fields.omit('screening_venue')
266        if not getattr(self.context, 'screening_date'):
267            form_fields = form_fields.omit('screening_date')
268        return form_fields
269
270class CustomApplicantManageFormPage(ApplicantManageFormPage):
271    """A full edit view for applicant data.
272    """
273
274    @property
275    def form_fields(self):
276        if self.context.special:
[14865]277            form_fields = grok.AutoFields(ICustomSpecialApplicant)
[14721]278            form_fields['applicant_id'].for_display = True
279            return form_fields
[16026]280        if self.target in ('conv', 'hndfincl', 'ndfincl'):
[15576]281            form_fields = grok.AutoFields(ICustomSpecialApplicant)
282            form_fields = form_fields.omit(
[15592]283                'special_application',
284                'carryover_courses_1',
285                'carryover_courses_2',
[15576]286                'locked', 'suspended')
[15579]287            form_fields['applicant_id'].for_display = True
[15576]288            return form_fields
[14721]289        form_fields = grok.AutoFields(ICustomUGApplicant)
290        if self.context.is_nd:
291            for field in ND_OMIT_MANAGE_FIELDS:
292                form_fields = form_fields.omit(field)
293        else:
294            for field in UG_OMIT_MANAGE_FIELDS:
295                form_fields = form_fields.omit(field)
296        form_fields['student_id'].for_display = True
297        form_fields['applicant_id'].for_display = True
298        return form_fields
299
[14865]300    def setUpWidgets(self, ignore_request=False):
301        super(CustomApplicantManageFormPage,self).setUpWidgets(ignore_request)
302        if self.context.special:
[15592]303            self.widgets['carryover_courses_1'].height = 3
304            self.widgets['carryover_courses_2'].height = 3
[14865]305        return
306
[14721]307class CustomApplicantEditFormPage(ApplicantEditFormPage):
308    """An applicant-centered edit view for applicant data.
309    """
310
[14807]311    def unremovable(self, ticket):
312        return True
313
[14721]314    @property
315    def form_fields(self):
316        if self.context.special:
[14865]317            form_fields = grok.AutoFields(ICustomSpecialApplicant).omit(
[14721]318                'locked', 'suspended')
319            form_fields['applicant_id'].for_display = True
320            return form_fields
[16026]321        if self.target in ('conv', 'hndfincl', 'ndfincl'):
[15576]322            form_fields = grok.AutoFields(ICustomSpecialApplicant)
323            form_fields = form_fields.omit(
[15592]324                'special_application',
325                'carryover_courses_1',
326                'carryover_courses_2',
[15576]327                'locked', 'suspended')
[15579]328            form_fields['applicant_id'].for_display = True
[15576]329            return form_fields
[14721]330        form_fields = grok.AutoFields(ICustomUGApplicantEdit)
331        if self.context.is_nd:
332            for field in ND_OMIT_EDIT_FIELDS:
333                form_fields = form_fields.omit(field)
334        elif self.target is not None and self.target.startswith('pre'):
335            for field in PRE_OMIT_EDIT_FIELDS:
336                form_fields = form_fields.omit(field)
337        else:
338            for field in UG_OMIT_EDIT_FIELDS:
339                form_fields = form_fields.omit(field)
340        form_fields['applicant_id'].for_display = True
341        form_fields['reg_number'].for_display = True
[14732]342        return form_fields
343
[14865]344    def setUpWidgets(self, ignore_request=False):
345        super(CustomApplicantEditFormPage,self).setUpWidgets(ignore_request)
346        if self.context.special:
[15592]347            self.widgets['carryover_courses_1'].height = 3
348            self.widgets['carryover_courses_2'].height = 3
[14865]349        return
350
[14807]351    @property
352    def display_actions(self):
353        state = IWorkflowState(self.context).getState()
354        # If the form is unlocked, applicants are allowed to save the form
355        # and remove unused tickets.
356        actions = [[_('Save')], []]
357        # Only in state started they can also add tickets.
358        if state == STARTED:
359            actions = [[_('Save')],
360                [_('Add online payment ticket'),]]
361        # In state paid, they can submit the data and further add tickets
362        # if the application is special.
363        elif self.context.special and state == PAID:
364            actions = [[_('Save'), _('Finally Submit')],
365                [_('Add online payment ticket'),]]
366        elif state == PAID:
367            actions = [[_('Save'), _('Finally Submit')], []]
368        return actions
369
[14732]370class CustomApplicationFeePaymentAddPage(ApplicationFeePaymentAddPage):
371    """ Page to add an online payment ticket
372    """
373
374    @property
375    def custom_requirements(self):
376        store = getUtility(IExtFileStore)
[15576]377        if not store.getFileByContext(self.context, attr=u'passport.jpg') \
378            and self.context.__parent__.with_picture:
[14732]379            return _('Upload your passport photo before making payment.')
[15580]380        return ''
381
382class CustomApplicantBaseDisplayFormPage(ApplicantBaseDisplayFormPage):
383
384    grok.context(ICustomApplicant)
385
386    @property
387    def form_fields(self):
[16026]388        if self.context.__parent__.prefix in (
389            'conv', 'special', 'hndfincl', 'ndfincl'):
[15580]390            form_fields = grok.AutoFields(ICustomApplicant).select(
391                'applicant_id', 'reg_number', 'email')
392            form_fields['reg_number'].field.title = u'Identification Number'
393            return form_fields
394        form_fields = grok.AutoFields(ICustomApplicant).select(
395            'applicant_id', 'reg_number', 'email', 'course1')
396        return form_fields
397
398class CustomExportPDFPaymentSlipPage(NigeriaExportPDFPaymentSlipPage):
399    """Deliver a PDF slip of the context.
400    """
401
402    grok.context(ICustomApplicantOnlinePayment)
403
404    @property
405    def form_fields(self):
406        form_fields = grok.AutoFields(ICustomApplicantOnlinePayment).omit(
407            'ac', 'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item',
408            'p_split_data')
409        form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
410        form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
[16026]411        if self.context.__parent__.__parent__.prefix in (
412            'conv', 'special', 'hndfincl', 'ndfincl'):
[15580]413            form_fields = form_fields.omit('p_session')
414        return form_fields
415
416    def render(self):
417        if self.payment_slip_download_warning:
418            self.flash(self.payment_slip_download_warning, type='danger')
419            self.redirect(self.url(self.context))
420            return
421        applicantview = CustomApplicantBaseDisplayFormPage(self.context.__parent__,
422            self.request)
423        students_utils = getUtility(IStudentsUtils)
424        return students_utils.renderPDF(self,'payment_slip.pdf',
425            self.context.__parent__, applicantview, note=self.note)
Note: See TracBrowser for help on using the repository browser.