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

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

Payment slip must not be downloadable before adding surcharges.

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