source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/students/browser.py @ 15505

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

Omit p_split_data on pdf slips.

  • Property svn:keywords set to Id
File size: 16.3 KB
RevLine 
[8862]1## $Id: browser.py 15470 2019-06-21 08:09:17Z henrik $
2##
3## Copyright (C) 2012 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##
18import grok
19from zope.formlib.textwidgets import BytesDisplayWidget
20from zope.component import getUtility
[13856]21from zope.security import checkPermission
[8862]22from zope.i18n import translate
[13620]23from datetime import datetime
[8862]24from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
[13623]25from waeup.kofa.interfaces import IExtFileStore, IObjectHistory, IKofaUtils
[13620]26from waeup.kofa.browser.layout import action, UtilityView
[13623]27from waeup.kofa.utils.helpers import get_current_principal, to_timezone
[8862]28from waeup.kofa.students.browser import (
[8904]29    StudentPersonalDisplayFormPage, StudentPersonalManageFormPage,
[8862]30    StudentClearanceManageFormPage, StudentClearanceEditFormPage,
[13058]31    StudentClearanceDisplayFormPage, OnlinePaymentFakeApproveView,
32    ExportPDFClearanceSlip, StudentBaseManageFormPage,
[8966]33    StudentBaseDisplayFormPage,
[13623]34    StudentBasePDFFormPage,
[8862]35    StudentBaseEditFormPage, StudentPersonalEditFormPage,
36    OnlinePaymentDisplayFormPage, OnlinePaymentAddFormPage,
[13058]37    OnlinePaymentBreadcrumb, ExportPDFPaymentSlip,
38    ExportPDFCourseRegistrationSlip,
39    ExportPDFBedTicketSlip,
[13458]40    StudentFilesUploadPage, emit_lock_message,
41    AccommodationManageFormPage)
[10707]42from waeup.kofa.students.interfaces import IStudentsUtils
[8862]43from waeup.kofa.students.viewlets import (
44    PaymentReceiptActionButton, StudentPassportActionButton)
45from kofacustom.nigeria.students.interfaces import (
[8863]46    INigeriaStudentBase, INigeriaStudent, INigeriaStudentPersonal,
[9564]47    INigeriaStudentPersonalEdit,
[8863]48    INigeriaUGStudentClearance,INigeriaPGStudentClearance,
[8904]49    INigeriaStudentOnlinePayment
[8862]50    )
51from waeup.kofa.students.workflow import ADMITTED
52from kofacustom.nigeria.interfaces import MessageFactory as _
53
[8863]54class NigeriaOnlinePaymentBreadcrumb(OnlinePaymentBreadcrumb):
[8862]55    """A breadcrumb for payments.
56    """
[8863]57    grok.context(INigeriaStudentOnlinePayment)
[8862]58
59class PaymentReceiptActionButton(PaymentReceiptActionButton):
60    grok.order(4)
[8863]61    grok.context(INigeriaStudentOnlinePayment)
[8862]62
[8966]63class NigeriaStudentBaseDisplayFormPage(StudentBaseDisplayFormPage):
64    """ Page to display student base data
65    """
[9704]66    form_fields = grok.AutoFields(INigeriaStudentBase).omit(
[14274]67        'password', 'suspended', 'suspended_comment',
68        'flash_notice', 'provisionally_cleared')
[13620]69    form_fields[
70        'financial_clearance_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
[8966]71
[8863]72class NigeriaStudentBaseManageFormPage(StudentBaseManageFormPage):
[8862]73    """ View to manage student base data
74    """
[9144]75    form_fields = grok.AutoFields(INigeriaStudentBase).omit(
[13620]76        'student_id', 'adm_code', 'suspended',
77        'financially_cleared_by', 'financial_clearance_date')
[8862]78
[8863]79class NigeriaStudentBaseEditFormPage(StudentBaseEditFormPage):
[8862]80    """ View to edit student base data
81    """
[8863]82    form_fields = grok.AutoFields(INigeriaStudentBase).select(
[8862]83        'email', 'phone')
84
[8863]85class NigeriaStudentPersonalDisplayFormPage(StudentPersonalDisplayFormPage):
[8862]86    """ Page to display student personal data
87    """
[9562]88    form_fields = grok.AutoFields(INigeriaStudentPersonal)
[8862]89    form_fields['perm_address'].custom_widget = BytesDisplayWidget
[9053]90    form_fields['next_kin_address'].custom_widget = BytesDisplayWidget
[9562]91    form_fields[
92        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
[8862]93
[8863]94class NigeriaStudentPersonalEditFormPage(StudentPersonalEditFormPage):
[8862]95    """ Page to edit personal data
96    """
[9564]97    form_fields = grok.AutoFields(INigeriaStudentPersonalEdit).omit('personal_updated')
[8862]98
[8904]99class NigeriaStudentPersonalManageFormPage(StudentPersonalManageFormPage):
100    """ Page to edit personal data
101    """
102    form_fields = grok.AutoFields(INigeriaStudentPersonal)
[9554]103    form_fields['personal_updated'].for_display = True
[9572]104    form_fields[
105        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
[8904]106
[8863]107class NigeriaStudentClearanceDisplayFormPage(StudentClearanceDisplayFormPage):
[8862]108    """ Page to display student clearance data
109    """
110
111    @property
112    def form_fields(self):
[9248]113        if self.context.is_postgrad:
[8862]114            form_fields = grok.AutoFields(
[8863]115                INigeriaPGStudentClearance).omit('clearance_locked')
[8862]116        else:
117            form_fields = grok.AutoFields(
[8863]118                INigeriaUGStudentClearance).omit('clearance_locked')
[9535]119        if not getattr(self.context, 'officer_comment'):
120            form_fields = form_fields.omit('officer_comment')
121        else:
122            form_fields['officer_comment'].custom_widget = BytesDisplayWidget
[8862]123        return form_fields
124
[13058]125class NigeriaExportPDFClearanceSlip(ExportPDFClearanceSlip):
[8862]126    """Deliver a PDF slip of the context.
127    """
[9704]128    omit_fields = ('password', 'suspended', 'suspended_comment',
[13712]129        'phone', 'adm_code', 'email', 'date_of_birth', 'current_level',
130        'flash_notice')
[8862]131
132    @property
133    def form_fields(self):
[9248]134        if self.context.is_postgrad:
[8862]135            form_fields = grok.AutoFields(
[8863]136                INigeriaPGStudentClearance).omit('clearance_locked')
[8862]137        else:
138            form_fields = grok.AutoFields(
[8863]139                INigeriaUGStudentClearance).omit('clearance_locked')
[9535]140        if not getattr(self.context, 'officer_comment'):
141            form_fields = form_fields.omit('officer_comment')
[8862]142        return form_fields
143
[8863]144class NigeriaStudentClearanceManageFormPage(StudentClearanceManageFormPage):
[8862]145    """ Page to edit student clearance data
146    """
147
148    @property
149    def form_fields(self):
[9248]150        if self.context.is_postgrad:
[9249]151            form_fields = grok.AutoFields(
152                INigeriaPGStudentClearance).omit('clr_code')
[8862]153        else:
[9249]154            form_fields = grok.AutoFields(
155                INigeriaUGStudentClearance).omit('clr_code')
[8862]156        return form_fields
157
[8863]158class NigeriaStudentClearanceEditFormPage(StudentClearanceEditFormPage):
[8862]159    """ View to edit student clearance data by student
160    """
161
162    @property
163    def form_fields(self):
[9248]164        if self.context.is_postgrad:
[8946]165            form_fields = grok.AutoFields(INigeriaPGStudentClearance).omit(
[12107]166            'clearance_locked', 'nysc_location', 'clr_code', 'officer_comment',
[12120]167            'physical_clearance_date')
[8862]168        else:
[8946]169            form_fields = grok.AutoFields(INigeriaUGStudentClearance).omit(
[12107]170            'clearance_locked', 'clr_code', 'officer_comment',
[12120]171            'physical_clearance_date')
[8862]172        return form_fields
173
[13058]174class NigeriaExportPDFCourseRegistrationSlip(ExportPDFCourseRegistrationSlip):
[9376]175    """Deliver a PDF slip of the context.
176    """
[9704]177    omit_fields = ('password', 'suspended', 'suspended_comment',
[13712]178        'phone', 'adm_code', 'sex', 'email', 'date_of_birth', 'current_level',
179        'flash_notice')
[9376]180
[8863]181class NigeriaOnlinePaymentDisplayFormPage(OnlinePaymentDisplayFormPage):
[8862]182    """ Page to view an online payment ticket
183    """
[8863]184    grok.context(INigeriaStudentOnlinePayment)
[9774]185    form_fields = grok.AutoFields(INigeriaStudentOnlinePayment).omit(
[9985]186        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
[8862]187    form_fields[
188        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
189    form_fields[
190        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
191
[8863]192class NigeriaOnlinePaymentAddFormPage(OnlinePaymentAddFormPage):
[8862]193    """ Page to add an online payment ticket
194    """
[8863]195    form_fields = grok.AutoFields(INigeriaStudentOnlinePayment).select(
[8862]196        'p_category')
197
[13058]198class NigeriaOnlinePaymentFakeApproveView(OnlinePaymentFakeApproveView):
[8862]199    """ Disable payment approval view for students.
200
201    This view is used for browser tests only and
202    has to be neutralized here!
203    """
204    grok.name('fake_approve')
205    grok.require('waeup.managePortal')
206
207    def update(self):
208        return
209
[13058]210class NigeriaExportPDFPaymentSlip(ExportPDFPaymentSlip):
[8862]211    """Deliver a PDF slip of the context.
212    """
[8863]213    grok.context(INigeriaStudentOnlinePayment)
[9774]214    form_fields = grok.AutoFields(INigeriaStudentOnlinePayment).omit(
[15470]215        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item',
216        'p_split_data')
[8862]217    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
218    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
[9704]219    omit_fields = ('password', 'suspended', 'suspended_comment', 'phone',
[13712]220        'adm_code', 'sex', 'email', 'date_of_birth', 'current_level',
221        'flash_notice')
[8862]222
[13458]223class NigeriaAccommodationManageFormPage(AccommodationManageFormPage):
224    """ Page to manage bed tickets.
225    This manage form page is for both students and students officers.
226    """
227    with_hostel_selection = False
228
[13058]229class NigeriaExportPDFBedTicketSlip(ExportPDFBedTicketSlip):
[9376]230    """Deliver a PDF slip of the context.
231    """
[9704]232    omit_fields = ('password', 'suspended', 'suspended_comment',
[13712]233        'phone', 'adm_code', 'email', 'date_of_birth', 'current_level',
234        'flash_notice')
[9376]235
[8862]236class StudentPassportActionButton(StudentPassportActionButton):
237
238    @property
239    def target_url(self):
[10707]240        # Passport pictures must not be editable if application slip
241        # exists.
[8862]242        slip = getUtility(IExtFileStore).getFileByContext(
243            self.context, 'application_slip')
[13130]244        PORTRAIT_CHANGE_STATES = getUtility(IStudentsUtils).PORTRAIT_CHANGE_STATES
245        if self.context.state not in PORTRAIT_CHANGE_STATES or slip is not None:
[8862]246            return ''
247        return self.view.url(self.view.context, self.target)
248
[8863]249class NigeriaStudentFilesUploadPage(StudentFilesUploadPage):
[8862]250    """ View to upload passport picture.
251
252    Students are not allowed to change the picture if they
253    passed the regular Kofa application.
254    """
255
256    def update(self):
[10707]257        # Passport pictures must not be editable if application slip
258        # exists.
[8862]259        slip = getUtility(IExtFileStore).getFileByContext(
260            self.context, 'application_slip')
[13130]261        PORTRAIT_CHANGE_STATES = getUtility(IStudentsUtils).PORTRAIT_CHANGE_STATES
262        if self.context.state not in PORTRAIT_CHANGE_STATES or slip is not None:
[8862]263            emit_lock_message(self)
264            return
265        super(StudentFilesUploadPage, self).update()
[13620]266        return
267
268class ClearStudentFinancially(UtilityView, grok.View):
[13634]269    """ Clear student financially by financial clearance officer
[13620]270    """
271    grok.context(INigeriaStudent)
272    grok.name('clear_financially')
273    grok.require('waeup.clearStudentFinancially')
274
275    def update(self):
276        if self.context.financially_cleared_by:
277            self.flash(_('This student has already been financially cleared.'),
278                       type="danger")
279            self.redirect(self.url(self.context))
280            return
281        user = get_current_principal()
282        if user is None:
283            usertitle = 'system'
284        else:
285            usertitle = getattr(user, 'public_name', None)
286            if not usertitle:
287                usertitle = user.title
288        self.context.financially_cleared_by = usertitle
289        self.context.financial_clearance_date = datetime.utcnow()
290        self.context.writeLogMessage(self,'financially cleared')
291        history = IObjectHistory(self.context)
292        history.addMessage('Financially cleared')
293        self.flash(_('Student has been financially cleared.'))
294        self.redirect(self.url(self.context))
295        return
296
297    def render(self):
298        return
299
300class WithdrawFinancialClearance(UtilityView, grok.View):
[13634]301    """ Withdraw financial clearance by financial clearance officer
[13620]302    """
303    grok.context(INigeriaStudent)
304    grok.name('withdraw_financial_clearance')
305    grok.require('waeup.clearStudentFinancially')
306
307    def update(self):
308        if not self.context.financially_cleared_by:
309            self.flash(_('This student has not yet been financially cleared.'),
310                       type="danger")
311            self.redirect(self.url(self.context))
312            return
313        self.context.financially_cleared_by = None
314        self.context.financial_clearance_date = None
315        self.context.writeLogMessage(self,'financial clearance withdrawn')
316        history = IObjectHistory(self.context)
317        history.addMessage('Financial clearance withdrawn')
318        self.flash(_('Financial clearance withdrawn.'))
319        self.redirect(self.url(self.context))
320        return
321
322    def render(self):
[13623]323        return
324
325cleared_note = """
326<br /><br /><br />
327<strong>Financially cleared on %s by %s.</strong>
328
329"""
330
[13634]331class NigeriaExportPDFFinancialClearancePage(UtilityView, grok.View):
332    """Deliver a PDF financial clearance slip.
[13623]333    """
334    grok.context(INigeriaStudent)
[13781]335    grok.name('fee_payment_history.pdf')
[13623]336    grok.require('waeup.viewStudent')
337    prefix = 'form'
338
339    omit_fields = (
340        'suspended', 'phone',
341        'adm_code', 'suspended_comment',
[13712]342        'date_of_birth', 'current_level',
343        'flash_notice')
[13623]344
345    form_fields = None
346
347    @property
348    def label(self):
349        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13787]350        return translate(_('Fee Payment History for'),
[13623]351            'waeup.kofa', target_language=portal_language) \
352            + ' %s' % self.context.display_fullname
353
354    def _sigsInFooter(self):
[14163]355        if not checkPermission('waeup.clearStudentFinancially', self.context):
356            return ()
[13642]357        return (_('Date, Checking Officer Signature'),
358                _('Date, Approving Officer Signature'),
[13623]359                )
360
361    @property
362    def note(self):
363        if self.context.financially_cleared_by:
364            tz = getUtility(IKofaUtils).tzinfo
365            try:
366                timestamp = to_timezone(
367                    self.context.financial_clearance_date, tz).strftime(
368                        "%Y-%m-%d %H:%M:%S")
369            except ValueError:
[13760]370                return
[13623]371            return cleared_note % (
372                timestamp, self.context.financially_cleared_by)
[13760]373        return
[13623]374
375    @property
376    def tabletitle(self):
377        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
378        tabletitle = []
379        tabletitle.append(translate(_('Successful Payments'), 'waeup.kofa',
380            target_language=portal_language))
381        return tabletitle
382
383    def render(self):
384        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
385        P_ID = translate(_('Payment Id'), 'waeup.kofa', target_language=portal_language)
386        #CD = translate(_('Creation Date'), 'waeup.kofa', target_language=portal_language)
387        PD = translate(_('Payment Date'), 'waeup.kofa', target_language=portal_language)
388        CAT = translate(_('Payment Category'), 'waeup.kofa', target_language=portal_language)
389        ITEM = translate(_('Payment Item'), 'waeup.kofa', target_language=portal_language)
390        AMT = translate(_('Amount (Naira)'), 'waeup.kofa', target_language=portal_language)
391        SSS = translate(_('Payment Session'), 'waeup.kofa', target_language=portal_language)
392        studentview = StudentBasePDFFormPage(self.context.student,
393            self.request, self.omit_fields)
394        students_utils = getUtility(IStudentsUtils)
395
396        tabledata = []
397        tableheader = []
398        tabledata.append(sorted(
399            [value for value in self.context['payments'].values()
[14279]400             if value.p_state in ('paid', 'waived')], key=lambda value: value.p_session))
[13634]401        tableheader.append([(P_ID,'p_id', 4.2),
[13623]402                         #(CD,'creation_date', 3),
403                         (PD,'formatted_p_date', 3),
404                         (CAT,'category', 3),
405                         (ITEM, 'p_item', 3),
406                         (AMT, 'amount_auth', 2),
407                         (SSS, 'p_session', 2),
408                         ])
409        return students_utils.renderPDF(
[13634]410            self, 'financial_clearance_slip.pdf',
[13623]411            self.context.student, studentview,
412            tableheader=tableheader,
413            tabledata=tabledata,
414            signatures=None,
415            sigs_in_footer=self._sigsInFooter(),
416            omit_fields=self.omit_fields,
417            note=self.note
418            )
Note: See TracBrowser for help on using the repository browser.