source: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/browser.py @ 17126

Last change on this file since 17126 was 17033, checked in by Henrik Bettermann, 2 years ago

Restructure text imports.

  • Property svn:keywords set to Id
File size: 20.6 KB
Line 
1## $Id: browser.py 17033 2022-07-26 08:58:05Z 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
19import os
20from zope.i18n import translate
21from zope.schema.interfaces import ConstraintNotSatisfied
22from zope.component import getUtility
23from zope.security import checkPermission
24from zope.formlib.textwidgets import BytesDisplayWidget
25from hurry.workflow.interfaces import IWorkflowInfo
26from waeup.kofa.interfaces import (
27    REQUESTED, ADMITTED, CLEARANCE, REQUESTED, CLEARED,
28    IExtFileStore, IKofaUtils, academic_sessions_vocab)
29from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
30from waeup.kofa.browser.layout import (
31    action, jsaction, UtilityView, KofaEditFormPage)
32from waeup.kofa.students.browser import (
33    StudyLevelEditFormPage, StudyLevelDisplayFormPage,
34    StudentBasePDFFormPage, ExportPDFCourseRegistrationSlip,
35    CourseTicketDisplayFormPage, StudentTriggerTransitionFormPage,
36    StartClearancePage, BalancePaymentAddFormPage,
37    ExportPDFAdmissionSlip, ExportPDFPersonalDataSlip,
38    PaymentsManageFormPage,
39    msave, emit_lock_message)
40from waeup.kofa.students.interfaces import (
41    IStudentsUtils, ICourseTicket, IStudent)
42from waeup.kofa.students.vocabularies import StudyLevelSource
43from waeup.kofa.students.workflow import FORBIDDEN_POSTGRAD_TRANS
44from kofacustom.nigeria.students.browser import (
45    NigeriaOnlinePaymentDisplayFormPage,
46    NigeriaStudentBaseDisplayFormPage,
47    NigeriaStudentBaseManageFormPage,
48    NigeriaStudentClearanceEditFormPage,
49    NigeriaOnlinePaymentAddFormPage,
50    NigeriaExportPDFPaymentSlip,
51    NigeriaExportPDFClearanceSlip,
52    NigeriaExportPDFCourseRegistrationSlip,
53    NigeriaStudentBaseEditFormPage,
54    NigeriaBedTicketAddPage,
55    NigeriaAccommodationManageFormPage,
56    NigeriaAccommodationDisplayFormPage,
57    NigeriaStudentPersonalManageFormPage,
58    NigeriaStudentPersonalEditFormPage,
59    NigeriaStudentPersonalDisplayFormPage
60    )
61from kofacustom.iuokada.students.interfaces import (
62    ICustomStudentOnlinePayment, ICustomStudentStudyCourse,
63    ICustomStudentStudyLevel, ICustomStudentBase, ICustomStudent,
64    ICustomStudentPersonal, ICustomStudentPersonalEdit)
65from kofacustom.iuokada.interfaces import MessageFactory as _
66
67class CustomStudentBaseDisplayFormPage(NigeriaStudentBaseDisplayFormPage):
68    """ Page to display student base data
69    """
70    form_fields = grok.AutoFields(ICustomStudentBase).omit(
71        'password', 'suspended', 'suspended_comment', 'flash_notice')
72
73class CustomStudentBaseManageFormPage(NigeriaStudentBaseManageFormPage):
74    """ View to manage student base data
75    """
76    form_fields = grok.AutoFields(ICustomStudentBase).omit(
77        'student_id', 'adm_code', 'suspended',
78        'financially_cleared_by', 'financial_clearance_date')
79
80class StudentBaseEditFormPage(NigeriaStudentBaseEditFormPage):
81    """ View to edit student base data
82    """
83    @property
84    def form_fields(self):
85        form_fields = grok.AutoFields(ICustomStudentBase).select(
86            'email', 'email2', 'parents_email', 'phone',)
87        if not self.context.state in (ADMITTED, CLEARANCE):
88            form_fields['parents_email'].for_display = True
89        return form_fields
90
91class CustomExportPDFCourseRegistrationSlip(
92    NigeriaExportPDFCourseRegistrationSlip):
93    """Deliver a PDF slip of the context.
94    """
95
96    def _signatures(self):
97        return (
98                ['Student Signature'],
99                ['HoD / Course Adviser Signature'],
100                ['College Officer Signature'],
101                ['Dean Signature']
102                )
103
104    #def _sigsInFooter(self):
105    #    return (_('Student'),
106    #            _('HoD / Course Adviser'),
107    #            _('College Officer'),
108    #            _('Dean'),
109    #            )
110    #    return ()
111
112class CustomStudentPersonalDisplayFormPage(NigeriaStudentPersonalDisplayFormPage):
113    """ Page to display student personal data
114    """
115    form_fields = grok.AutoFields(ICustomStudentPersonal)
116    form_fields['perm_address'].custom_widget = BytesDisplayWidget
117    form_fields['postal_address'].custom_widget = BytesDisplayWidget
118    form_fields['hostel_address'].custom_widget = BytesDisplayWidget
119    form_fields['father_address'].custom_widget = BytesDisplayWidget
120    form_fields['mother_address'].custom_widget = BytesDisplayWidget
121    form_fields['guardian_address'].custom_widget = BytesDisplayWidget
122    form_fields[
123        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
124
125
126class CustomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage):
127    """ Page to edit personal data
128    """
129    form_fields = grok.AutoFields(ICustomStudentPersonalEdit).omit(
130        'personal_updated')
131
132    def update(self):
133        #if not self.context.is_fresh:
134        #    self.flash('Not allowed.', type="danger")
135        #    self.redirect(self.url(self.context))
136        #    return
137        if not self.context.minimumStudentPayments():
138            self.flash('Please make 40% of your tution fee payments first.',
139                       type="warning")
140            self.redirect(self.url(self.context, 'view_personal'))
141            return
142        super(CustomStudentPersonalEditFormPage, self).update()
143        return
144
145
146class CustomStudentPersonalManageFormPage(NigeriaStudentPersonalManageFormPage):
147    """ Page to manage personal data
148    """
149    form_fields = grok.AutoFields(ICustomStudentPersonal)
150    form_fields['personal_updated'].for_display = True
151    form_fields[
152        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
153
154class CustomExportPDFPersonalDataSlip(ExportPDFPersonalDataSlip):
155    """Deliver a PDF base and personal data slip.
156    """
157    grok.name('course_registration_clearance.pdf')
158    omit_fields = (
159        'phone', 'email',
160        'suspended',
161        'adm_code', 'suspended_comment',
162        'current_level',
163        'flash_notice', 'entry_session',
164        'parents_email')
165
166    form_fields = grok.AutoFields(ICustomStudentPersonal)
167
168    def _signatures(self):
169        return ([('I certify that the above named student has satisfied the financial requirements for registration.', 'Name and Signature of Bursary Staff', '<br><br>')],
170                [('I certify that the credentials of the student have been screened by me and the student is hereby cleared.', 'Name and Signature of Registry Staff', '<br><br>')],
171                [('I certify that the above named student has registered with the Library.', 'Name and Signature of Library Staff', '<br><br>')],
172                [('I certify that the above named student has been registered with the college. ', 'Name and Signature of College Officer', '<br><br>')],
173                [('I certify that the above named student has completed his/her ICT registration. ', 'Name and Signature of ICT Staff', '<br><br>')],
174                [('Eligibility/Congratulation Station', 'Name and Signature of Registrar', '')],
175                )
176
177    @property
178    def tabletitle(self):
179        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
180        tabletitle = []
181        session = self.context.student.current_session
182        tabletitle.append('_PB_Successful %s/%s Session Payments' %(session, session+1))
183        return tabletitle
184
185    def render(self):
186        if not self.context.minimumStudentPayments():
187            self.redirect(self.url(self.context))
188            return
189        studentview = StudentBasePDFFormPage(self.context.student,
190            self.request, self.omit_fields)
191        students_utils = getUtility(IStudentsUtils)
192
193        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
194        P_ID = translate(_('Payment Id'), 'waeup.kofa', target_language=portal_language)
195        #CD = translate(_('Creation Date'), 'waeup.kofa', target_language=portal_language)
196        PD = translate(_('Payment Date'), 'waeup.kofa', target_language=portal_language)
197        CAT = translate(_('Payment Category'), 'waeup.kofa', target_language=portal_language)
198        ITEM = translate(_('Payment Item'), 'waeup.kofa', target_language=portal_language)
199        AMT = translate(_('Amount (Naira)'), 'waeup.kofa', target_language=portal_language)
200        SSS = translate(_('Payment Session'), 'waeup.kofa', target_language=portal_language)
201        tabledata = []
202        tableheader = []
203        tabledata.append(sorted(
204            [value for value in self.context['payments'].values()
205             if value.p_state in ('paid', 'waived', 'scholarship')
206             and value.p_session >= value.student.current_session],
207             key=lambda value: value.p_session))
208        tableheader.append([(P_ID,'p_id', 4.2),
209                         #(CD,'creation_date', 3),
210                         (PD,'formatted_p_date', 3),
211                         (CAT,'category', 3),
212                         (ITEM, 'p_item', 3),
213                         (AMT, 'amount_auth', 2),
214                         (SSS, 'p_session', 2),
215                         ])
216
217        #watermark_path = os.path.join(
218        #    os.path.dirname(__file__), 'static', 'watermark.pdf')
219        #watermark = open(watermark_path, 'rb')
220        #file_path = os.path.join(
221        #    os.path.dirname(__file__), 'static', 'biodataPage2.pdf')
222        #file = open(file_path, 'rb')
223        #mergefiles = [file,]
224
225        return students_utils.renderPDF(
226            self, 'course_registration_clearance.pdf',
227            self.context.student, studentview,
228            omit_fields=self.omit_fields,
229            signatures=self._signatures(),
230
231            tableheader=tableheader,
232            tabledata=tabledata,
233
234            pagebreak=True,
235        #    mergefiles=mergefiles,
236        #    watermark=watermark
237            )
238
239class CustomAccommodationDisplayFormPage(NigeriaAccommodationDisplayFormPage):
240    """ Page to view bed tickets.
241    """
242    with_hostel_selection = True
243
244class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
245    """ Page to manage bed tickets.
246    This manage form page is for both students and students officers.
247    """
248    with_hostel_selection = True
249
250class CustomBedTicketAddPage(NigeriaBedTicketAddPage):
251    """ Page to add a bed ticket
252    """
253    with_ac = False
254    with_bedselection = True
255
256class CustomPaymentsManageFormPage(PaymentsManageFormPage):
257    """ Page to manage the student payments. This manage form page is for
258    both students and students officers. IUOkada does not allow students
259    to remove any payment ticket.
260    """
261    grok.template('paymentsmanagepage')
262
263    @property
264    def manage_payments_allowed(self):
265        return checkPermission('waeup.manageStudent', self.context)
266
267    @property
268    def schoolfee_payments_made(self):
269        cs = self.context.student.current_session
270        SF_PAYMENTS = ('schoolfee', 'schoolfee40', 'secondinstal', 'clearance')
271        if cs > self.context.student.entry_session:
272            sf_paid = {cs-1: 0.0, cs: 0.0, cs+1: 0.0}
273            sessions = (cs-1, cs, cs+1)
274        else:
275            sf_paid = {cs: 0.0, cs+1: 0.0}
276            sessions = (cs, cs+1)
277        try:
278            certificate = self.context.student['studycourse'].certificate
279        except (AttributeError, TypeError):
280            return sf_paid, 0, 0
281        total_sf = 0.0
282        if self.context.student in (ADMITTED, CLEARANCE, REQUESTED, CLEARED):
283            sf = getattr(certificate, 'school_fee_1', 0.0)
284        else:
285            sf = getattr(certificate, 'school_fee_2', 0.0)
286        if sf is not None:
287            total_sf = sf
288        brought_fwd = 0.0
289        for ticket in self.context.values():
290            amt = ticket.net_amt
291            if not amt:
292                amt = ticket.amount_auth
293            if ticket.p_category in SF_PAYMENTS and \
294                ticket.p_state == 'paid' and \
295                ticket.p_session in sessions:
296                sf_paid[ticket.p_session] += amt
297            if ticket.p_state != 'paid' and\
298               ticket.p_category == 'brought_fwd':
299                  brought_fwd += ticket.amount_auth
300        return sf_paid, total_sf, brought_fwd
301
302class StudentGetMatricNumberPage(UtilityView, grok.View):
303    """ Construct and set the matriculation number.
304    """
305    grok.context(IStudent)
306    grok.name('get_matric_number')
307    grok.require('waeup.manageStudent')
308
309    def update(self):
310        students_utils = getUtility(IStudentsUtils)
311        msg, mnumber = students_utils.setMatricNumber(self.context)
312        if msg:
313            self.flash(msg, type="danger")
314        else:
315            self.flash(_('Matriculation number %s assigned.' % mnumber))
316            self.context.writeLogMessage(self, '%s assigned' % mnumber)
317        self.redirect(self.url(self.context))
318        return
319
320    def render(self):
321        return
322
323class SwitchLibraryAccessView(UtilityView, grok.View):
324    """ Switch the library attribute
325    """
326    grok.context(ICustomStudent)
327    grok.name('switch_library_access')
328    grok.require('waeup.switchLibraryAccess')
329
330    def update(self):
331        if self.context.library:
332            self.context.library = False
333            self.context.writeLogMessage(self, 'library access disabled')
334            self.flash(_('Library access disabled'))
335        else:
336            self.context.library = True
337            self.context.writeLogMessage(self, 'library access enabled')
338            self.flash(_('Library access enabled'))
339        self.redirect(self.url(self.context))
340        return
341
342    def render(self):
343        return
344
345class ExportLibIdCard(UtilityView, grok.View):
346    """Deliver an id card for the library.
347    """
348    grok.context(ICustomStudent)
349    grok.name('lib_idcard.pdf')
350    grok.require('waeup.viewStudent')
351    prefix = 'form'
352
353    label = u"Library Clearance"
354
355    omit_fields = (
356        'suspended', 'email', 'phone',
357        'adm_code', 'suspended_comment',
358        'date_of_birth',
359        'current_mode', 'certificate',
360        'entry_session',
361        'flash_notice')
362
363    form_fields = []
364
365    def _sigsInFooter(self):
366        isStudent = getattr(
367            self.request.principal, 'user_type', None) == 'student'
368        if isStudent:
369            return ''
370        return (_("Date, Reader's Signature"),
371                _("Date, Circulation Librarian's Signature"),
372                )
373
374    def update(self):
375        if not self.context.library:
376            self.flash(_('Forbidden!'), type="danger")
377            self.redirect(self.url(self.context))
378        return
379
380    @property
381    def note(self):
382        return """
383<br /><br /><br /><br /><font size='12'>
384This is to certify that the bearer whose photograph and other details appear
385 overleaf is a registered user of the <b>University Library</b>.
386 The card is not transferable. A replacement fee is charged for a loss,
387 mutilation or otherwise. If found, please, return to the University Library,
388 Igbinedion University, Okada.
389</font>
390
391"""
392        return
393
394    def render(self):
395        studentview = StudentBasePDFFormPage(self.context.student,
396            self.request, self.omit_fields)
397        students_utils = getUtility(IStudentsUtils)
398        return students_utils.renderPDF(
399            self, 'lib_idcard',
400            self.context.student, studentview,
401            omit_fields=self.omit_fields,
402            sigs_in_footer=self._sigsInFooter(),
403            note=self.note)
404
405class CustomStartClearancePage(StartClearancePage):
406    with_ac = False
407
408class CustomBalancePaymentAddFormPage(BalancePaymentAddFormPage):
409    grok.require('waeup.payStudent')
410
411from kofacustom.iuokada.students.admission_letter_ug import (
412    ADML_UG_1, ADML_UG_2, ADML_UG_3, ADML_UG_2_MEDICAL, ADML_UG_2_PHARMACY,
413    BASIC_MEDICAL_ONLY, BASIC_PHARMACY_ONLY)
414from kofacustom.iuokada.students.admission_letter_pg import ADML_PG
415from kofacustom.iuokada.students.admission_letter_pt import ADML_PT
416from kofacustom.iuokada.students.admission_letter_jupeb import ADML_JUPEB
417
418class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
419    """Deliver a PDF Admission slip.
420    """
421
422    omit_fields = ('date_of_birth',
423                   #'current_level',
424                   #'current_mode',
425                   #'entry_session'
426                   )
427
428    @property
429    def session(self):
430        return academic_sessions_vocab.getTerm(
431            self.context.entry_session).title
432
433    @property
434    def level(self):
435        studylevelsource = StudyLevelSource()
436        return studylevelsource.factory.getTitle(
437            self.context['studycourse'].certificate, self.context.current_level)
438
439    @property
440    def label(self):
441        return 'OFFER OF PROVISIONAL ADMISSION \nFOR %s SESSION' % self.session
442
443    @property
444    def pre_text_ug(self):
445        return (
446            'Following your performance in the screening exercise '
447            'for the %s academic session, I am pleased to inform '
448            'you that you have been offered provisional admission into the '
449            'Igbinedion University, Okada as follows:' % self.session)
450
451    @property
452    def pre_text_pg(self):
453        return (
454            'I am pleased to inform you that your application for admission'
455            ' into the Igbinedion University, Okada was successful. You have'
456            ' been admitted as follows:')
457
458    def render(self):
459        students_utils = getUtility(IStudentsUtils)
460        watermark_path = os.path.join(
461            os.path.dirname(__file__), 'static', 'watermark.pdf')
462        watermark = open(watermark_path, 'rb')
463        if self.context.is_jupeb:
464            return students_utils.renderPDFAdmissionLetter(self,
465                self.context.student, omit_fields=self.omit_fields,
466                pre_text=self.pre_text_ug, post_text=ADML_JUPEB,
467                watermark=watermark)
468        if self.context.current_mode.endswith('_pt'):
469            return students_utils.renderPDFAdmissionLetter(self,
470                self.context.student, omit_fields=self.omit_fields,
471                pre_text=self.pre_text_ug, post_text=ADML_PT,
472                watermark=watermark)
473        if self.context.is_postgrad:
474            file_path = os.path.join(
475                os.path.dirname(__file__), 'static', 'admission_letter_pg.pdf')
476            file = open(file_path, 'rb')
477            mergefiles = [file,]
478            return students_utils.renderPDFAdmissionLetter(self,
479                self.context.student, omit_fields=self.omit_fields,
480                pre_text=self.pre_text_pg, post_text=ADML_PG,
481                mergefiles=mergefiles,
482                watermark=watermark)
483        file_path = os.path.join(
484            os.path.dirname(__file__), 'static', 'admission_letter_ug.pdf')
485        file = open(file_path, 'rb')
486        mergefiles = [file,]
487        if self.context.certcode in ('BBMS', 'MBBS') and self.context.current_level == 100:
488            post_text = BASIC_MEDICAL_ONLY + ADML_UG_1 + ADML_UG_2_MEDICAL + ADML_UG_3
489        elif self.context.certcode in ('BPHARM',) and self.context.current_level == 100:
490            post_text = BASIC_PHARMACY_ONLY + ADML_UG_1 + ADML_UG_2_MEDICAL + ADML_UG_3
491        else:
492            post_text = ADML_UG_1 + ADML_UG_2 + ADML_UG_3
493        return students_utils.renderPDFAdmissionLetter(self,
494            self.context.student, omit_fields=self.omit_fields,
495            pre_text=self.pre_text_ug, post_text=post_text,
496            mergefiles=mergefiles,
497            watermark=watermark)
498
499class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage):
500    """ Page to view an online payment ticket. We do not omit provider_amt.
501    """
502    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
503        'gateway_amt', 'thirdparty_amt', 'p_item','p_combi', 'provider_amt')
504    form_fields[
505        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
506    form_fields[
507        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
508
509class CustomExportPDFPaymentSlip(NigeriaExportPDFPaymentSlip):
510    """Deliver a PDF slip of the context. We do not omit provider_amt.
511    """
512    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
513        'gateway_amt', 'thirdparty_amt', 'p_item',
514        'p_split_data','p_combi', 'provider_amt')
515    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
516    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
Note: See TracBrowser for help on using the repository browser.