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

Last change on this file since 17958 was 17866, checked in by Henrik Bettermann, 3 months ago

Implement final clearance.

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