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

Last change on this file since 16294 was 16292, checked in by Henrik Bettermann, 4 years ago

Redesign personal data slip completely.

  • Property svn:keywords set to Id
File size: 21.7 KB
Line 
1## $Id: browser.py 16292 2020-10-30 12:36:49Z 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.formlib.textwidgets import BytesDisplayWidget
24from hurry.workflow.interfaces import IWorkflowInfo
25from waeup.kofa.interfaces import (REQUESTED, ADMITTED, CLEARANCE,
26    IExtFileStore, IKofaUtils, academic_sessions_vocab)
27from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
28from waeup.kofa.browser.layout import (
29    action, jsaction, UtilityView, KofaEditFormPage)
30from waeup.kofa.students.browser import (
31    StudyLevelEditFormPage, StudyLevelDisplayFormPage,
32    StudentBasePDFFormPage, ExportPDFCourseRegistrationSlip,
33    CourseTicketDisplayFormPage, StudentTriggerTransitionFormPage,
34    StartClearancePage, BalancePaymentAddFormPage,
35    ExportPDFAdmissionSlip, ExportPDFPersonalDataSlip,
36    msave, emit_lock_message)
37from waeup.kofa.students.interfaces import (
38    IStudentsUtils, ICourseTicket, IStudent)
39from waeup.kofa.students.vocabularies import StudyLevelSource
40from waeup.kofa.students.workflow import FORBIDDEN_POSTGRAD_TRANS
41from kofacustom.nigeria.students.browser import (
42    NigeriaOnlinePaymentDisplayFormPage,
43    NigeriaStudentBaseDisplayFormPage,
44    NigeriaStudentBaseManageFormPage,
45    NigeriaStudentClearanceEditFormPage,
46    NigeriaOnlinePaymentAddFormPage,
47    NigeriaExportPDFPaymentSlip,
48    NigeriaExportPDFClearanceSlip,
49    NigeriaExportPDFCourseRegistrationSlip,
50    NigeriaStudentBaseEditFormPage,
51    NigeriaBedTicketAddPage,
52    NigeriaAccommodationManageFormPage,
53    NigeriaAccommodationDisplayFormPage,
54    NigeriaStudentPersonalManageFormPage,
55    NigeriaStudentPersonalEditFormPage,
56    NigeriaStudentPersonalDisplayFormPage
57    )
58from kofacustom.iuokada.students.interfaces import (
59    ICustomStudentOnlinePayment, ICustomStudentStudyCourse,
60    ICustomStudentStudyLevel, ICustomStudentBase, ICustomStudent,
61    ICustomStudentPersonal, ICustomStudentPersonalEdit)
62from kofacustom.iuokada.interfaces import MessageFactory as _
63
64class CustomStudentBaseDisplayFormPage(NigeriaStudentBaseDisplayFormPage):
65    """ Page to display student base data
66    """
67    form_fields = grok.AutoFields(ICustomStudentBase).omit(
68        'password', 'suspended', 'suspended_comment', 'flash_notice')
69
70class CustomStudentBaseManageFormPage(NigeriaStudentBaseManageFormPage):
71    """ View to manage student base data
72    """
73    form_fields = grok.AutoFields(ICustomStudentBase).omit(
74        'student_id', 'adm_code', 'suspended',
75        'financially_cleared_by', 'financial_clearance_date')
76
77class StudentBaseEditFormPage(NigeriaStudentBaseEditFormPage):
78    """ View to edit student base data
79    """
80    @property
81    def form_fields(self):
82        form_fields = grok.AutoFields(ICustomStudentBase).select(
83            'email', 'email2', 'parents_email', 'phone',)
84        if not self.context.state in (ADMITTED, CLEARANCE):
85            form_fields['parents_email'].for_display = True
86        return form_fields
87
88class CustomExportPDFCourseRegistrationSlip(
89    NigeriaExportPDFCourseRegistrationSlip):
90    """Deliver a PDF slip of the context.
91    """
92
93    def _signatures(self):
94        return (
95                ['Student Signature'],
96                ['HoD / Course Adviser Signature'],
97                ['College Officer Signature'],
98                ['Dean Signature']
99                )
100
101    #def _sigsInFooter(self):
102    #    return (_('Student'),
103    #            _('HoD / Course Adviser'),
104    #            _('College Officer'),
105    #            _('Dean'),
106    #            )
107    #    return ()
108
109class CustomStudentPersonalDisplayFormPage(NigeriaStudentPersonalDisplayFormPage):
110    """ Page to display student personal data
111    """
112    form_fields = grok.AutoFields(ICustomStudentPersonal)
113    form_fields['perm_address'].custom_widget = BytesDisplayWidget
114    form_fields['postal_address'].custom_widget = BytesDisplayWidget
115    form_fields['hostel_address'].custom_widget = BytesDisplayWidget
116    form_fields['father_address'].custom_widget = BytesDisplayWidget
117    form_fields['mother_address'].custom_widget = BytesDisplayWidget
118    form_fields['guardian_address'].custom_widget = BytesDisplayWidget
119    form_fields[
120        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
121
122
123class CustomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage):
124    """ Page to edit personal data
125    """
126    form_fields = grok.AutoFields(ICustomStudentPersonalEdit).omit(
127        'personal_updated')
128
129    def update(self):
130        if not self.context.is_fresh:
131            self.flash('Not allowed.', type="danger")
132            self.redirect(self.url(self.context))
133            return
134        minamount = 200000
135        if not self.context.minimumFreshStudentPayments(minamount):
136            self.flash('Please make required payments first '
137                       '(at least in the amount of %s Naira).' % minamount,
138                       type="warning")
139            self.redirect(self.url(self.context, 'view_personal'))
140            return
141        super(CustomStudentPersonalEditFormPage, self).update()
142        return
143
144
145class CustomStudentPersonalManageFormPage(NigeriaStudentPersonalManageFormPage):
146    """ Page to edit personal data
147    """
148    form_fields = grok.AutoFields(ICustomStudentPersonal)
149    form_fields['personal_updated'].for_display = True
150    form_fields[
151        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
152
153class CustomExportPDFPersonalDataSlip(ExportPDFPersonalDataSlip):
154    """Deliver a PDF base and personal data slip.
155    """
156    grok.name('course_registration_clearance.pdf')
157    omit_fields = (
158        'phone', 'email',
159        'suspended',
160        'adm_code', 'suspended_comment',
161        'current_level',
162        'flash_notice', 'entry_session',
163        'parents_email')
164
165    form_fields = grok.AutoFields(ICustomStudentPersonal)
166
167    def _signatures(self):
168        return ([('I certify that the above named student has satisfied the financial requirements for registration.', 'Name and Signature of Bursary Staff', '<br><br>')],
169                [('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>')],
170                [('I certify that the above named student has registered with the Library.', 'Name and Signature of Library Staff', '<br><br>')],
171                [('I certify that the above named student has been registered with the college. ', 'Name and Signature of College Officer', '<br><br>')],
172                [('I certify that the above named student has completed his/her ICT registration. ', 'Name and Signature of ICT Staff', '<br><br>')],
173                [('Eligibility/Congratulation Station', 'Name and Signature of Registrar', '')],
174                )
175
176    def render(self):
177        studentview = StudentBasePDFFormPage(self.context.student,
178            self.request, self.omit_fields)
179        students_utils = getUtility(IStudentsUtils)
180
181        #watermark_path = os.path.join(
182        #    os.path.dirname(__file__), 'static', 'watermark.pdf')
183        #watermark = open(watermark_path, 'rb')
184        #file_path = os.path.join(
185        #    os.path.dirname(__file__), 'static', 'biodataPage2.pdf')
186        #file = open(file_path, 'rb')
187        #mergefiles = [file,]
188
189        return students_utils.renderPDF(
190            self, 'course_registration_clearance.pdf',
191            self.context.student, studentview,
192            omit_fields=self.omit_fields,
193            signatures=self._signatures(),
194            pagebreak=True,
195        #    mergefiles=mergefiles,
196        #    watermark=watermark
197            )
198
199class CustomAccommodationDisplayFormPage(NigeriaAccommodationDisplayFormPage):
200    """ Page to view bed tickets.
201    """
202    with_hostel_selection = True
203
204class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
205    """ Page to manage bed tickets.
206    This manage form page is for both students and students officers.
207    """
208    with_hostel_selection = True
209
210class CustomBedTicketAddPage(NigeriaBedTicketAddPage):
211    """ Page to add a bed ticket
212    """
213    with_ac = False
214    with_bedselection = True
215
216class StudentGetMatricNumberPage(UtilityView, grok.View):
217    """ Construct and set the matriculation number.
218    """
219    grok.context(IStudent)
220    grok.name('get_matric_number')
221    grok.require('waeup.manageStudent')
222
223    def update(self):
224        students_utils = getUtility(IStudentsUtils)
225        msg, mnumber = students_utils.setMatricNumber(self.context)
226        if msg:
227            self.flash(msg, type="danger")
228        else:
229            self.flash(_('Matriculation number %s assigned.' % mnumber))
230            self.context.writeLogMessage(self, '%s assigned' % mnumber)
231        self.redirect(self.url(self.context))
232        return
233
234    def render(self):
235        return
236
237class SwitchLibraryAccessView(UtilityView, grok.View):
238    """ Switch the library attribute
239    """
240    grok.context(ICustomStudent)
241    grok.name('switch_library_access')
242    grok.require('waeup.switchLibraryAccess')
243
244    def update(self):
245        if self.context.library:
246            self.context.library = False
247            self.context.writeLogMessage(self, 'library access disabled')
248            self.flash(_('Library access disabled'))
249        else:
250            self.context.library = True
251            self.context.writeLogMessage(self, 'library access enabled')
252            self.flash(_('Library access enabled'))
253        self.redirect(self.url(self.context))
254        return
255
256    def render(self):
257        return
258
259class ExportLibIdCard(UtilityView, grok.View):
260    """Deliver an id card for the library.
261    """
262    grok.context(ICustomStudent)
263    grok.name('lib_idcard.pdf')
264    grok.require('waeup.viewStudent')
265    prefix = 'form'
266
267    label = u"Library Clearance"
268
269    omit_fields = (
270        'suspended', 'email', 'phone',
271        'adm_code', 'suspended_comment',
272        'date_of_birth',
273        'current_mode', 'certificate',
274        'entry_session',
275        'flash_notice')
276
277    form_fields = []
278
279    def _sigsInFooter(self):
280        isStudent = getattr(
281            self.request.principal, 'user_type', None) == 'student'
282        if isStudent:
283            return ''
284        return (_("Date, Reader's Signature"),
285                _("Date, Circulation Librarian's Signature"),
286                )
287
288    def update(self):
289        if not self.context.library:
290            self.flash(_('Forbidden!'), type="danger")
291            self.redirect(self.url(self.context))
292        return
293
294    @property
295    def note(self):
296        return """
297<br /><br /><br /><br /><font size='12'>
298This is to certify that the bearer whose photograph and other details appear
299 overleaf is a registered user of the <b>University Library</b>.
300 The card is not transferable. A replacement fee is charged for a loss,
301 mutilation or otherwise. If found, please, return to the University Library,
302 Igbinedion University, Okada.
303</font>
304
305"""
306        return
307
308    def render(self):
309        studentview = StudentBasePDFFormPage(self.context.student,
310            self.request, self.omit_fields)
311        students_utils = getUtility(IStudentsUtils)
312        return students_utils.renderPDF(
313            self, 'lib_idcard',
314            self.context.student, studentview,
315            omit_fields=self.omit_fields,
316            sigs_in_footer=self._sigsInFooter(),
317            note=self.note)
318
319class CustomStartClearancePage(StartClearancePage):
320    with_ac = False
321
322class CustomBalancePaymentAddFormPage(BalancePaymentAddFormPage):
323    grok.require('waeup.payStudent')
324
325class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
326    """Deliver a PDF Admission slip.
327    """
328
329    omit_fields = ('date_of_birth',
330                   #'current_level',
331                   'current_mode',
332                   #'entry_session'
333                   )
334
335    @property
336    def session(self):
337        return academic_sessions_vocab.getTerm(
338            self.context.entry_session).title
339
340    @property
341    def level(self):
342        studylevelsource = StudyLevelSource()
343        return studylevelsource.factory.getTitle(
344            self.context['studycourse'].certificate, self.context.current_level)
345
346    @property
347    def label(self):
348        return 'OFFER OF PROVISIONAL ADMISSION \nFOR %s SESSION' % self.session
349
350    @property
351    def pre_text_ug(self):
352        return (
353            'Following your performance in the screening exercise '
354            'for the %s academic session, I am pleased to inform '
355            'you that you have been offered provisional admission into the '
356            'Igbinedion University, Okada as follows:' % self.session)
357
358    @property
359    def pre_text_pg(self):
360        return (
361            'I am pleased to inform you that your application for admission'
362            ' into the Igbinedion University, Okada was successful. You have'
363            ' been admitted as follows:')
364
365    @property
366    def post_text_ug(self):
367        return """
368Please note that at the point of registration for your programme of study (course), you will be required to present the following documents: Current UTME result slip, WAEC/NECO (0' Level) result, Birth certificate or sworn affidavit of age, and health certificate from a recognized Medical Centre.
369
370All credentials (original) will be checked during registration. This admission will be cancelled at any point in time it is found that your claims in the application form are false.
371
372You are required to show evidence of the result / credentials you presented on application for admission.
373
374Fees can be paid using any of the following options:
375
376Fees can be paid through your portal page. INSTRUCTIONS can be found below "FEES PAYMENT PROCEDURE" for the options you have to make your payment, as well as instructions on how to use your preferred payment option. If you choose to use the bank payment option, you can pay at any branch of the following banks through Etranzact platform only: Access Bank, First Bank, Zenith Bank
377
378Kindly note the following:
379
380Fees indicated on the Fee Structure page are valid for the current session only.
381Your Student Id (indicated above) Is your logln to the University portal.
382As an indication of your acceptance of this offer of admission, you should pay a non-refundable Acceptance deposit of 200,000. Further note that the 200,000 deposit is part of the tuition fee for the session. Failure to pay after the expiration of two weeks may lead to forfeiture of admission.
383All fees must be paid in full at the beginning of the session, as basis for accommodation, registration and attendance of lectures. This is the rule for all students at all levels. Install mental payments of not more than two installments, may be allowed under exceptional circumstances.
384Fees once paid are not refundable.
385It is advisable that you keep the original receipts of fees paid and present them on demand.
386
387Accommodation: Accommodation in University hostels is compulsory for every student. No student Is allowed to live outside the hostels. Any student who does so will be expelled from the University.
388
389Food: Food is available in cafeteria on "pay-as-you-eat" basis.
390
391Resumption Date: The University opens for fresh students with online registration starting from Monday 28th September, 2020. The date for physical resumption is 14th November, 2020.
392
393Registration/Orientation Programme: Orientation programme/registration for fresh students will start on Monday, 16th November 2020. Registration ends on 2020-11-30. A late registration fee of N50,000 will be charged after this date. All credentials, O'Level Results, Birth Certificate/Age Declaration, UTME Result Slip (Original) will be checked during registration. This admission will be cancelled at any point in time it is found that any of your claims in the application form is false.
394
395Transport Facility: The University provides a compulsory shuttle bus service to all students at a fee already included in the other charges.
396
397Kindly note that fresh students are not allowed the use of private vehicles.
398
399Conduct: All students are expected to conduct themselves properly and dress decently on campus, as well as obey all rules and regulations as failure to comply will attract appropriate sanctions.
400
401We wish you a successful academic career in Igbinedion University.
402
403Congratulations!
404
405
406
407<img src="${signature_benji_img_path}" valign="-20" height="38" width="86" />
408
409Friday Benji Bakare Esq.
410Registrar
411registrar@iuokada.edu.ng
41208035902949
413"""
414
415    @property
416    def post_text_pg(self):
417        return """
4181. Details of your programme will be made available to you by the Head of your Department on your arrival at the Igbinedion University.
419
4202. This offer is conditional upon the confirmation of your qualifications as listed by you in your application form. You will be required to produce the ORIGINAL COPIES of all your certificates for verification during registration. If at any time after admission, it is discovered that you do not possess any of the qualifications upon which this offer of admission was made, you will be required to withdraw from the University.
421
4223. If you accept this offer of admission upon the conditions above, you should please:
423
424(a) Complete the enclosed Acceptance Form of Provisional Offer of Admission in duplicate and send  by registered mail or by hand to the
425
426Secretary
427School of Postgraduate Studies and Research
428Igbinedion University,
429P.M.B. 0006,
430Benin City, Edo State,
431Nigeria
432
433(b)     Forward the following along with the Acceptance Form of Provisional Offer of Admission.
434
435(i) A non-refundable deposit of N100,000.00 (One Hundred Thousand Naira Only) which is part of the School fees: Payable Online.
436
437(ii) Four recent passport-size photograph of yourself with your full-names (surname first in BLOCK LETTERS) written on the reverse side of the photograph and pinned to the Acceptance Form.
438
4394. The following will be required for Registration:
440
441(a) A medical examination to be conducted by an approved medical practitioner. On your arrival at the Igbinedion University, you should submit the enclosed Igbinedion University Medical Examination Form duly completed and signed by an approved medical practitioner together with your chest X-ray film to Director of Health Service at the Igbinedion University, Okada.
442
443(b) The original copies of all credentials listed in your application form (including NYSC discharge/exemption certificate) should be brought for sighting.
444
4455. You are required to pay the necessary fees and register for your degree programme not later than three weeks from the beginning of the Academic Session. Late registration may be allowed during an additional period of five weeks on payment of a late registration fees. Please note that you will be allowed to register after two months have elapsed from the beginning of the sessions.
446
4476. Please find attached:
448
449(a) A copy of School fees Regime
450(b) A copy of Acceptance Forms
451
4527. Note:
453
454(a) All Tuition fees are to be paid online
455(b) Post-graduate dues and other charges are to be paid into ABC Microfinance Bank Okada, Account No: 30125
456
4578.  CONGRATULATIONS!!!
458
459Yours faithfully,
460
461Mr. Olaoke, Olasoji Oluwole
462Secretary, School of Postgraduate Studies & Research
463"""
464
465    def render(self):
466        students_utils = getUtility(IStudentsUtils)
467        watermark_path = os.path.join(
468            os.path.dirname(__file__), 'static', 'watermark.pdf')
469        watermark = open(watermark_path, 'rb')
470        if self.context.is_postgrad:
471            file_path = os.path.join(
472                os.path.dirname(__file__), 'static', 'admission_letter_pg.pdf')
473            file = open(file_path, 'rb')
474            mergefiles = [file,]
475            return students_utils.renderPDFAdmissionLetter(self,
476                self.context.student, omit_fields=self.omit_fields,
477                pre_text=self.pre_text_pg, post_text=self.post_text_pg,
478                mergefiles=mergefiles,
479                watermark=watermark)
480        file_path = os.path.join(
481            os.path.dirname(__file__), 'static', 'admission_letter_ug.pdf')
482        file = open(file_path, 'rb')
483        mergefiles = [file,]
484        return students_utils.renderPDFAdmissionLetter(self,
485            self.context.student, omit_fields=self.omit_fields,
486            pre_text=self.pre_text_ug, post_text=self.post_text_ug,
487            mergefiles=mergefiles,
488            watermark=watermark)
489
490class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage):
491    """ Page to view an online payment ticket. We do not omit provider_amt.
492    """
493    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
494        'gateway_amt', 'thirdparty_amt', 'p_item','p_combi', 'provider_amt')
495    form_fields[
496        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
497    form_fields[
498        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
499
500class CustomExportPDFPaymentSlip(NigeriaExportPDFPaymentSlip):
501    """Deliver a PDF slip of the context. We do not omit provider_amt.
502    """
503    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
504        'gateway_amt', 'thirdparty_amt', 'p_item',
505        'p_split_data','p_combi', 'provider_amt')
506    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
507    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
Note: See TracBrowser for help on using the repository browser.