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

Last change on this file since 15518 was 15518, checked in by Henrik Bettermann, 6 years ago

Improve code.

  • Property svn:keywords set to Id
File size: 12.5 KB
RevLine 
[10765]1## $Id: browser.py 15518 2019-07-24 22:02:22Z 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,
36    ExportJobContainerDownload)
37from waeup.kofa.browser.viewlets import ManageActionButton
[14721]38from waeup.kofa.applicants.viewlets import (
39    PaymentReceiptActionButton, PDFActionButton)
40from waeup.kofa.applicants.pdf import PDFApplicationSlip
[14807]41from waeup.kofa.applicants.workflow import ADMITTED, PAID, STARTED
[14721]42from kofacustom.nigeria.applicants.interfaces import (
43    UG_OMIT_DISPLAY_FIELDS,
44    UG_OMIT_PDF_FIELDS,
45    UG_OMIT_MANAGE_FIELDS,
46    UG_OMIT_EDIT_FIELDS
47    )
48from kofacustom.dspg.applicants.interfaces import (
49    ICustomUGApplicant, ICustomUGApplicantEdit,
[14865]50    ICustomSpecialApplicant,
[14721]51    ND_OMIT_DISPLAY_FIELDS,
52    ND_OMIT_PDF_FIELDS,
53    ND_OMIT_MANAGE_FIELDS,
54    ND_OMIT_EDIT_FIELDS
55    )
[10765]56
[14732]57from kofacustom.dspg.interfaces import MessageFactory as _
58
[14721]59UG_OMIT_EDIT_FIELDS = [
60    value for value in UG_OMIT_EDIT_FIELDS
61        if not value in ('jamb_subjects', 'jamb_score', 'jamb_reg_number')]
[10765]62
[14721]63PRE_OMIT_EDIT_FIELDS = UG_OMIT_EDIT_FIELDS + [
64    'firstname',
65    'middlename',
66    'lastname',
67    #'sex',
68    'jamb_score'
69    ]
70
[15498]71##### Bursary exports
72
73class BursaryExportPaymentsActionButton(ManageActionButton):
74    """ 'Export payment data' button for faculties.
75    """
76    grok.context(IApplicantsContainer)
77    grok.view(ApplicantsContainerPage)
78    grok.require('waeup.exportBursaryData')
79    icon = 'actionicon_down.png'
80    text = _('Export payment data')
81    grok.order(4)
82
[15518]83    @property
84    def target_url(self):
85        return self.view.url(self.view.context) + '/exports/bursary.html'
86
[15498]87class BursaryExportJobContainerOverview(ExportJobContainerOverview):
88    """Page that lists active applicant data export jobs and provides links
89    to discard or download CSV files.
90    """
91    grok.require('waeup.exportBursaryData')
[15518]92    grok.name('bursary.html')
[15498]93
94    def update(self, CREATE=None, DISCARD=None, job_id=None):
95        if CREATE:
96            self.redirect(self.url('@@start_bursary_export'))
97            return
98        if DISCARD and job_id:
99            entry = self.context.entry_from_job_id(job_id)
100            self.context.delete_export_entry(entry)
101            ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
102            self.context.logger.info(
103                '%s - discarded: job_id=%s' % (ob_class, job_id))
104            self.flash(_('Discarded export') + ' %s' % job_id)
105        self.entries = doll_up(self, user=self.request.principal.id)
106        return
107
108class  BursaryExportJobContainerJobStart(ExportJobContainerJobStart):
109    """View that starts export job.
110    """
111    grok.require('waeup.exportBursaryData')
112    grok.name('start_bursary_export')
113
114    def update(self):
115        utils = queryUtility(IKofaUtils)
116        if not utils.expensive_actions_allowed():
117            self.flash(_(
118                "Currently, exporters cannot be started due to high "
119                "system load. Please try again later."), type='danger')
120            self.entries = doll_up(self, user=None)
121            return
122
123        ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
124        container_code = self.context.__parent__.code
125        # Start payments exporter
126        exporter = 'applicantpayments'
127        job_id = self.context.start_export_job(exporter,
128                                      self.request.principal.id,
129                                      container=container_code)
130        self.context.logger.info(
131            '%s - exported: %s (%s), job_id=%s'
132            % (ob_class, exporter, container_code, job_id))
133
134        self.flash(_('Exports started.'))
[15518]135        self.redirect(self.url(self.context, 'bursary.html'))
[15498]136        return
137
138    def render(self):
139        return
140
141class BursaryExportJobContainerDownload(ExportJobContainerDownload):
142    """Page that downloads a students export csv file.
143
144    """
145    grok.require('waeup.exportBursaryData')
146    grok.context(IApplicantsContainer)
147
[14721]148class CustomApplicantsContainerPage(ApplicantsContainerPage):
149    """The standard view for regular applicant containers.
150    """
151
152    @property
153    def form_fields(self):
154        form_fields = super(CustomApplicantsContainerPage, self).form_fields
155        if self.request.principal.id == 'zope.anybody':
156            return form_fields.omit('application_fee')
157        return form_fields
158
159class CustomApplicantDisplayFormPage(ApplicantDisplayFormPage):
160    """A display view for applicant data.
161    """
162
163    @property
164    def form_fields(self):
165        if self.context.special:
[14865]166            return grok.AutoFields(ICustomSpecialApplicant)
[14721]167        form_fields = grok.AutoFields(ICustomUGApplicant)
168        if self.context.is_nd:
169            for field in ND_OMIT_DISPLAY_FIELDS:
170                form_fields = form_fields.omit(field)
171        else:
172            form_fields = grok.AutoFields(ICustomUGApplicant)
173            for field in UG_OMIT_DISPLAY_FIELDS:
174                form_fields = form_fields.omit(field)
175        form_fields['notice'].custom_widget = BytesDisplayWidget
176        form_fields['jamb_subjects'].custom_widget = BytesDisplayWidget
177        if not getattr(self.context, 'student_id'):
178            form_fields = form_fields.omit('student_id')
179        if not getattr(self.context, 'screening_score'):
180            form_fields = form_fields.omit('screening_score')
181        if not getattr(self.context, 'screening_venue'):
182            form_fields = form_fields.omit('screening_venue')
183        if not getattr(self.context, 'screening_date'):
184            form_fields = form_fields.omit('screening_date')
185        return form_fields
186
187class CustomPDFApplicationSlip(PDFApplicationSlip):
188
189    def _reduced_slip(self):
190        return getattr(self.context, 'result_uploaded', False)
191
192    @property
193    def note(self):
194        note = getattr(self.context.__parent__, 'application_slip_notice', None)
195        if note:
196            return '<br /><br />' + note
197        pronoun = 'S/he'
198        if self.context.sex == 'm':
199            pronoun = 'He'
200        else:
201            pronoun = 'She'
202        return '''<br /><br />
203The applicant has declared that:
204
205a) %s is not a member of any secret cult and will not join any.
206b) %s will not engage in any cult activities.
207c) %s will not be involved in any acts of terrorism, rape, robbery, fighting, illegal gathering and
208any activities that could disrupt peace on campus.
209d) %s does not have and will not acquire any form of weapon, fire arms, gun knife or any weapon
210that can cause damage to life and property.
211e) %s will strive to be worthy in character and learning at all times.
212
213The applicant has acknowledged that offences will automatically lead to the expulsion from the
214Polytechnic and also be dealt with in accordance with the law of the land.
215
216The applicant promises to abide by all the Rules and Regulations of the Polytechnic if offered
217admission.
218''' % (
219    pronoun, pronoun, pronoun, pronoun, pronoun)
220
221    @property
222    def form_fields(self):
223        form_fields = grok.AutoFields(ICustomUGApplicant)
224        if self.context.is_nd:
225            for field in ND_OMIT_PDF_FIELDS:
226                form_fields = form_fields.omit(field)
227        else:
228            form_fields = grok.AutoFields(ICustomUGApplicant)
229            for field in UG_OMIT_PDF_FIELDS:
230                form_fields = form_fields.omit(field)
231        if not getattr(self.context, 'student_id'):
232            form_fields = form_fields.omit('student_id')
233        if not getattr(self.context, 'screening_score'):
234            form_fields = form_fields.omit('screening_score')
235        if not getattr(self.context, 'screening_venue'):
236            form_fields = form_fields.omit('screening_venue')
237        if not getattr(self.context, 'screening_date'):
238            form_fields = form_fields.omit('screening_date')
239        return form_fields
240
241class CustomApplicantManageFormPage(ApplicantManageFormPage):
242    """A full edit view for applicant data.
243    """
244
245    @property
246    def form_fields(self):
247        if self.context.special:
[14865]248            form_fields = grok.AutoFields(ICustomSpecialApplicant)
[14721]249            form_fields['applicant_id'].for_display = True
250            return form_fields
251        form_fields = grok.AutoFields(ICustomUGApplicant)
252        if self.context.is_nd:
253            for field in ND_OMIT_MANAGE_FIELDS:
254                form_fields = form_fields.omit(field)
255        else:
256            for field in UG_OMIT_MANAGE_FIELDS:
257                form_fields = form_fields.omit(field)
258        form_fields['student_id'].for_display = True
259        form_fields['applicant_id'].for_display = True
260        return form_fields
261
[14865]262    def setUpWidgets(self, ignore_request=False):
263        super(CustomApplicantManageFormPage,self).setUpWidgets(ignore_request)
264        if self.context.special:
265            self.widgets['carryover_courses'].height = 3
266        return
267
[14721]268class CustomApplicantEditFormPage(ApplicantEditFormPage):
269    """An applicant-centered edit view for applicant data.
270    """
271
[14807]272    def unremovable(self, ticket):
273        return True
274
[14721]275    @property
276    def form_fields(self):
277        if self.context.special:
[14865]278            form_fields = grok.AutoFields(ICustomSpecialApplicant).omit(
[14721]279                'locked', 'suspended')
280            form_fields['applicant_id'].for_display = True
281            return form_fields
282        form_fields = grok.AutoFields(ICustomUGApplicantEdit)
283        if self.context.is_nd:
284            for field in ND_OMIT_EDIT_FIELDS:
285                form_fields = form_fields.omit(field)
286        elif self.target is not None and self.target.startswith('pre'):
287            for field in PRE_OMIT_EDIT_FIELDS:
288                form_fields = form_fields.omit(field)
289        else:
290            for field in UG_OMIT_EDIT_FIELDS:
291                form_fields = form_fields.omit(field)
292        form_fields['applicant_id'].for_display = True
293        form_fields['reg_number'].for_display = True
[14732]294        return form_fields
295
[14865]296    def setUpWidgets(self, ignore_request=False):
297        super(CustomApplicantEditFormPage,self).setUpWidgets(ignore_request)
298        if self.context.special:
299            self.widgets['carryover_courses'].height = 3
300        return
301
[14807]302    @property
303    def display_actions(self):
304        state = IWorkflowState(self.context).getState()
305        # If the form is unlocked, applicants are allowed to save the form
306        # and remove unused tickets.
307        actions = [[_('Save')], []]
308        # Only in state started they can also add tickets.
309        if state == STARTED:
310            actions = [[_('Save')],
311                [_('Add online payment ticket'),]]
312        # In state paid, they can submit the data and further add tickets
313        # if the application is special.
314        elif self.context.special and state == PAID:
315            actions = [[_('Save'), _('Finally Submit')],
316                [_('Add online payment ticket'),]]
317        elif state == PAID:
318            actions = [[_('Save'), _('Finally Submit')], []]
319        return actions
320
[14732]321class CustomApplicationFeePaymentAddPage(ApplicationFeePaymentAddPage):
322    """ Page to add an online payment ticket
323    """
324
325    @property
326    def custom_requirements(self):
327        store = getUtility(IExtFileStore)
328        if not store.getFileByContext(self.context, attr=u'passport.jpg'):
329            return _('Upload your passport photo before making payment.')
330        return ''
Note: See TracBrowser for help on using the repository browser.