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

Last change on this file since 14086 was 14030, checked in by Henrik Bettermann, 8 years ago

Also students should be able to print signature fields in the footer.

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