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

Last change on this file since 15554 was 15536, checked in by Henrik Bettermann, 5 years ago

Wrong context.

  • Property svn:keywords set to Id
File size: 12.5 KB
Line 
1## $Id: browser.py 15536 2019-08-03 08:25: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
21from zope.component import getUtility, queryUtility
22from zope.i18n import translate
23from hurry.workflow.interfaces import IWorkflowState
24from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
25from zope.formlib.textwidgets import BytesDisplayWidget
26from waeup.kofa.interfaces import IExtFileStore, IKofaUtils
27from waeup.kofa.browser.pages import doll_up
28from waeup.kofa.applicants.interfaces import (
29    IApplicant, IApplicantEdit,
30    IApplicantsContainer,)
31from waeup.kofa.applicants.browser import (ApplicantDisplayFormPage,
32    ApplicantManageFormPage, ApplicantEditFormPage,
33    ApplicantsContainerPage, ApplicationFeePaymentAddPage,
34    ExportJobContainerOverview,
35    ExportJobContainerJobStart,
36    ExportJobContainerDownload)
37from waeup.kofa.browser.viewlets import ManageActionButton
38from waeup.kofa.applicants.viewlets import (
39    PaymentReceiptActionButton, PDFActionButton)
40from waeup.kofa.applicants.pdf import PDFApplicationSlip
41from waeup.kofa.applicants.workflow import ADMITTED, PAID, STARTED
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,
50    ICustomSpecialApplicant,
51    ND_OMIT_DISPLAY_FIELDS,
52    ND_OMIT_PDF_FIELDS,
53    ND_OMIT_MANAGE_FIELDS,
54    ND_OMIT_EDIT_FIELDS
55    )
56
57from kofacustom.dspg.interfaces import MessageFactory as _
58
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')]
62
63PRE_OMIT_EDIT_FIELDS = UG_OMIT_EDIT_FIELDS + [
64    'firstname',
65    'middlename',
66    'lastname',
67    #'sex',
68    'jamb_score'
69    ]
70
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
83    @property
84    def target_url(self):
85        return self.view.url(self.view.context) + '/exports/bursary.html'
86
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')
92    grok.name('bursary.html')
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.'))
135        self.redirect(self.url(self.context, 'bursary.html'))
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
147class CustomApplicantsContainerPage(ApplicantsContainerPage):
148    """The standard view for regular applicant containers.
149    """
150
151    @property
152    def form_fields(self):
153        form_fields = super(CustomApplicantsContainerPage, self).form_fields
154        if self.request.principal.id == 'zope.anybody':
155            return form_fields.omit('application_fee')
156        return form_fields
157
158class CustomApplicantDisplayFormPage(ApplicantDisplayFormPage):
159    """A display view for applicant data.
160    """
161
162    @property
163    def form_fields(self):
164        if self.context.special:
165            return grok.AutoFields(ICustomSpecialApplicant)
166        form_fields = grok.AutoFields(ICustomUGApplicant)
167        if self.context.is_nd:
168            for field in ND_OMIT_DISPLAY_FIELDS:
169                form_fields = form_fields.omit(field)
170        else:
171            form_fields = grok.AutoFields(ICustomUGApplicant)
172            for field in UG_OMIT_DISPLAY_FIELDS:
173                form_fields = form_fields.omit(field)
174        form_fields['notice'].custom_widget = BytesDisplayWidget
175        form_fields['jamb_subjects'].custom_widget = BytesDisplayWidget
176        if not getattr(self.context, 'student_id'):
177            form_fields = form_fields.omit('student_id')
178        if not getattr(self.context, 'screening_score'):
179            form_fields = form_fields.omit('screening_score')
180        if not getattr(self.context, 'screening_venue'):
181            form_fields = form_fields.omit('screening_venue')
182        if not getattr(self.context, 'screening_date'):
183            form_fields = form_fields.omit('screening_date')
184        return form_fields
185
186class CustomPDFApplicationSlip(PDFApplicationSlip):
187
188    def _reduced_slip(self):
189        return getattr(self.context, 'result_uploaded', False)
190
191    @property
192    def note(self):
193        note = getattr(self.context.__parent__, 'application_slip_notice', None)
194        if note:
195            return '<br /><br />' + note
196        pronoun = 'S/he'
197        if self.context.sex == 'm':
198            pronoun = 'He'
199        else:
200            pronoun = 'She'
201        return '''<br /><br />
202The applicant has declared that:
203
204a) %s is not a member of any secret cult and will not join any.
205b) %s will not engage in any cult activities.
206c) %s will not be involved in any acts of terrorism, rape, robbery, fighting, illegal gathering and
207any activities that could disrupt peace on campus.
208d) %s does not have and will not acquire any form of weapon, fire arms, gun knife or any weapon
209that can cause damage to life and property.
210e) %s will strive to be worthy in character and learning at all times.
211
212The applicant has acknowledged that offences will automatically lead to the expulsion from the
213Polytechnic and also be dealt with in accordance with the law of the land.
214
215The applicant promises to abide by all the Rules and Regulations of the Polytechnic if offered
216admission.
217''' % (
218    pronoun, pronoun, pronoun, pronoun, pronoun)
219
220    @property
221    def form_fields(self):
222        form_fields = grok.AutoFields(ICustomUGApplicant)
223        if self.context.is_nd:
224            for field in ND_OMIT_PDF_FIELDS:
225                form_fields = form_fields.omit(field)
226        else:
227            form_fields = grok.AutoFields(ICustomUGApplicant)
228            for field in UG_OMIT_PDF_FIELDS:
229                form_fields = form_fields.omit(field)
230        if not getattr(self.context, 'student_id'):
231            form_fields = form_fields.omit('student_id')
232        if not getattr(self.context, 'screening_score'):
233            form_fields = form_fields.omit('screening_score')
234        if not getattr(self.context, 'screening_venue'):
235            form_fields = form_fields.omit('screening_venue')
236        if not getattr(self.context, 'screening_date'):
237            form_fields = form_fields.omit('screening_date')
238        return form_fields
239
240class CustomApplicantManageFormPage(ApplicantManageFormPage):
241    """A full edit view for applicant data.
242    """
243
244    @property
245    def form_fields(self):
246        if self.context.special:
247            form_fields = grok.AutoFields(ICustomSpecialApplicant)
248            form_fields['applicant_id'].for_display = True
249            return form_fields
250        form_fields = grok.AutoFields(ICustomUGApplicant)
251        if self.context.is_nd:
252            for field in ND_OMIT_MANAGE_FIELDS:
253                form_fields = form_fields.omit(field)
254        else:
255            for field in UG_OMIT_MANAGE_FIELDS:
256                form_fields = form_fields.omit(field)
257        form_fields['student_id'].for_display = True
258        form_fields['applicant_id'].for_display = True
259        return form_fields
260
261    def setUpWidgets(self, ignore_request=False):
262        super(CustomApplicantManageFormPage,self).setUpWidgets(ignore_request)
263        if self.context.special:
264            self.widgets['carryover_courses'].height = 3
265        return
266
267class CustomApplicantEditFormPage(ApplicantEditFormPage):
268    """An applicant-centered edit view for applicant data.
269    """
270
271    def unremovable(self, ticket):
272        return True
273
274    @property
275    def form_fields(self):
276        if self.context.special:
277            form_fields = grok.AutoFields(ICustomSpecialApplicant).omit(
278                'locked', 'suspended')
279            form_fields['applicant_id'].for_display = True
280            return form_fields
281        form_fields = grok.AutoFields(ICustomUGApplicantEdit)
282        if self.context.is_nd:
283            for field in ND_OMIT_EDIT_FIELDS:
284                form_fields = form_fields.omit(field)
285        elif self.target is not None and self.target.startswith('pre'):
286            for field in PRE_OMIT_EDIT_FIELDS:
287                form_fields = form_fields.omit(field)
288        else:
289            for field in UG_OMIT_EDIT_FIELDS:
290                form_fields = form_fields.omit(field)
291        form_fields['applicant_id'].for_display = True
292        form_fields['reg_number'].for_display = True
293        return form_fields
294
295    def setUpWidgets(self, ignore_request=False):
296        super(CustomApplicantEditFormPage,self).setUpWidgets(ignore_request)
297        if self.context.special:
298            self.widgets['carryover_courses'].height = 3
299        return
300
301    @property
302    def display_actions(self):
303        state = IWorkflowState(self.context).getState()
304        # If the form is unlocked, applicants are allowed to save the form
305        # and remove unused tickets.
306        actions = [[_('Save')], []]
307        # Only in state started they can also add tickets.
308        if state == STARTED:
309            actions = [[_('Save')],
310                [_('Add online payment ticket'),]]
311        # In state paid, they can submit the data and further add tickets
312        # if the application is special.
313        elif self.context.special and state == PAID:
314            actions = [[_('Save'), _('Finally Submit')],
315                [_('Add online payment ticket'),]]
316        elif state == PAID:
317            actions = [[_('Save'), _('Finally Submit')], []]
318        return actions
319
320class CustomApplicationFeePaymentAddPage(ApplicationFeePaymentAddPage):
321    """ Page to add an online payment ticket
322    """
323
324    @property
325    def custom_requirements(self):
326        store = getUtility(IExtFileStore)
327        if not store.getFileByContext(self.context, attr=u'passport.jpg'):
328            return _('Upload your passport photo before making payment.')
329        return ''
Note: See TracBrowser for help on using the repository browser.