source: main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/students/browser.py @ 12396

Last change on this file since 12396 was 12396, checked in by Henrik Bettermann, 10 years ago

physical_clearance_date must not be edited by students.

  • Property svn:keywords set to Id
File size: 19.1 KB
Line 
1## $Id: browser.py 12396 2015-01-04 20:20:21Z 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.i18n import translate
20from zope.formlib.textwidgets import BytesDisplayWidget
21from zope.component import getUtility
22from waeup.kofa.interfaces import IKofaUtils
23from waeup.kofa.browser.layout import UtilityView
24from waeup.kofa.students.interfaces import IStudentsUtils
25from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
26from waeup.kofa.students.browser import (
27    StartClearancePage, BedTicketAddPage, ExportPDFAdmissionSlipPage,
28    StudentBasePDFFormPage)
29from waeup.kwarapoly.students.interfaces import (
30    ICustomStudent, ICustomStudentBase, ICustomStudentStudyLevel,
31    ICustomUGStudentClearance, ICustomPGStudentClearance)
32from waeup.kwarapoly.interfaces import MessageFactory as _
33from waeup.kofa.students.workflow import (
34    ADMITTED, PAID, REQUESTED, RETURNING, CLEARED, REGISTERED,
35    VALIDATED, GRADUATED, TRANSCRIPT, CREATED, CLEARANCE)
36from kofacustom.nigeria.students.browser import (
37    NigeriaOnlinePaymentDisplayFormPage,
38    NigeriaOnlinePaymentAddFormPage,
39    NigeriaExportPDFPaymentSlipPage,
40    NigeriaStudentClearanceDisplayFormPage,
41    NigeriaExportPDFClearanceSlipPage,
42    NigeriaStudentClearanceEditFormPage,
43    NigeriaExportPDFCourseRegistrationSlipPage,
44    NigeriaStudentPersonalDisplayFormPage,
45    NigeriaStudentClearanceManageFormPage,
46    NigeriaStudentPersonalEditFormPage,
47    NigeriaStudentPersonalManageFormPage,
48    NigeriaStudentBaseEditFormPage
49    )
50
51from waeup.kwarapoly.students.interfaces import (
52    ICustomStudentOnlinePayment,
53    ICustomStudentPersonal,
54    ICustomStudentPersonalEdit
55    )
56
57
58class CustomStudentBaseEditFormPage(NigeriaStudentBaseEditFormPage):
59    """ View to edit student base data
60    """
61    form_fields = grok.AutoFields(ICustomStudentBase).select(
62        'email', 'phone', 'sex')
63
64
65class CustomStudentPersonalDisplayFormPage(
66    NigeriaStudentPersonalDisplayFormPage):
67    """ Page to display student personal data
68    """
69    form_fields = grok.AutoFields(ICustomStudentPersonal)
70    form_fields['perm_address'].custom_widget = BytesDisplayWidget
71    form_fields['next_kin_address'].custom_widget = BytesDisplayWidget
72    form_fields['corr_address'].custom_widget = BytesDisplayWidget
73    form_fields['sponsor_address'].custom_widget = BytesDisplayWidget
74    form_fields[
75        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
76
77
78class CustomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage):
79    """ Page to edit personal data
80    """
81    form_fields = grok.AutoFields(ICustomStudentPersonalEdit).omit(
82        'personal_updated')
83
84
85class CustomStudentPersonalManageFormPage(
86    NigeriaStudentPersonalManageFormPage):
87    """ Page to edit personal data
88    """
89    form_fields = grok.AutoFields(ICustomStudentPersonal)
90    form_fields['personal_updated'].for_display = True
91    form_fields[
92        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
93
94
95class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage):
96    """ Page to view an online payment ticket
97    """
98    grok.context(ICustomStudentOnlinePayment)
99    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
100        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
101    form_fields[
102        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
103    form_fields[
104        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
105
106
107class CustomOnlinePaymentAddFormPage(NigeriaOnlinePaymentAddFormPage):
108    """ Page to add an online payment ticket
109    """
110    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).select(
111        'p_category')
112
113
114class CustomExportPDFPaymentSlipPage(NigeriaExportPDFPaymentSlipPage):
115    """Deliver a PDF slip of the context.
116    """
117    grok.context(ICustomStudentOnlinePayment)
118    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
119        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
120    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget(
121        'le')
122    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget(
123        'le')
124
125
126class CustomStartClearancePage(StartClearancePage):
127
128    with_ac = False
129
130
131class CustomStudentClearanceDisplayFormPage(
132    NigeriaStudentClearanceDisplayFormPage):
133    """ Page to display student clearance data
134    """
135
136    @property
137    def form_fields(self):
138        if self.context.is_postgrad:
139            form_fields = grok.AutoFields(
140                ICustomPGStudentClearance).omit('clearance_locked')
141        else:
142            form_fields = grok.AutoFields(
143                ICustomUGStudentClearance).omit('clearance_locked')
144        if not getattr(self.context, 'officer_comment'):
145            form_fields = form_fields.omit('officer_comment')
146        else:
147            form_fields['officer_comment'].custom_widget = BytesDisplayWidget
148        return form_fields
149
150
151class CustomExportPDFClearanceSlipPage(NigeriaExportPDFClearanceSlipPage):
152    """Deliver a PDF slip of the context.
153    """
154
155    @property
156    def form_fields(self):
157        if self.context.is_postgrad:
158            form_fields = grok.AutoFields(
159                ICustomPGStudentClearance).omit('clearance_locked')
160        else:
161            form_fields = grok.AutoFields(
162                ICustomUGStudentClearance).omit('clearance_locked')
163        if not getattr(self.context, 'officer_comment'):
164            form_fields = form_fields.omit('officer_comment')
165        return form_fields
166
167
168class CustomStudentClearanceManageFormPage(
169    NigeriaStudentClearanceManageFormPage):
170    """ Page to edit student clearance data
171    """
172
173    @property
174    def form_fields(self):
175        if self.context.is_postgrad:
176            form_fields = grok.AutoFields(
177                ICustomPGStudentClearance).omit('clr_code')
178        else:
179            form_fields = grok.AutoFields(
180                ICustomUGStudentClearance).omit('clr_code')
181        return form_fields
182
183
184class CustomStudentClearanceEditFormPage(NigeriaStudentClearanceEditFormPage):
185    """ View to edit student clearance data by student
186    """
187
188    def dataNotComplete(self):
189        return False
190
191    @property
192    def form_fields(self):
193        if self.context.is_postgrad:
194            form_fields = grok.AutoFields(ICustomPGStudentClearance).omit(
195            'clearance_locked', 'nysc_location', 'clr_code', 'officer_comment',
196            'physical_clearance_date')
197        else:
198            form_fields = grok.AutoFields(ICustomUGStudentClearance).omit(
199            'clearance_locked', 'clr_code', 'officer_comment',
200            'physical_clearance_date')
201        return form_fields
202
203
204class BedTicketAddPage(BedTicketAddPage):
205    """ Page to add an online payment ticket
206    """
207    buttonname = _('Create bed ticket')
208    notice = ''
209    with_ac = False
210
211
212class CustomExportPDFAdmissionSlipPage(ExportPDFAdmissionSlipPage):
213    """Deliver a PDF Admission slip.
214    """
215    grok.context(ICustomStudent)
216
217    omit_fields = ('date_of_birth', 'current_level')
218
219    form_fields = grok.AutoFields(ICustomStudent).select(
220        'student_id', 'reg_number')
221
222    def render(self):
223        if self.context.state in (CREATED, ADMITTED,
224                                  CLEARANCE, REQUESTED, CLEARED):
225            self.flash('Not allowed.')
226            self.redirect(self.url(self.context))
227            return
228        students_utils = getUtility(IStudentsUtils)
229        return students_utils.renderPDFAdmissionLetter(self,
230            self.context.student, omit_fields=self.omit_fields)
231
232
233class ExportPDFAdmissionNotificationPage(UtilityView, grok.View):
234    """Deliver a PDF Admission notification slip.
235    """
236    grok.context(ICustomStudent)
237    grok.name('admission_notification.pdf')
238    grok.require('waeup.viewStudent')
239    prefix = 'form'
240    label = 'Notification of Provisional Admission'
241
242    omit_fields = ('date_of_birth', 'current_level')
243
244    form_fields = grok.AutoFields(ICustomStudent).select(
245        'student_id', 'reg_number', 'sex', 'lga')
246
247    def render(self):
248        if self.context.state not in (ADMITTED, CLEARANCE, REQUESTED, CLEARED):
249            self.flash('Not allowed.')
250            self.redirect(self.url(self.context))
251            return
252        students_utils = getUtility(IStudentsUtils)
253        pre_text = ''
254        post_text = post_text_freshers
255        return students_utils.renderPDFAdmissionLetter(self,
256            self.context.student, omit_fields=self.omit_fields,
257            pre_text=pre_text, post_text=post_text)
258
259
260# copied from waeup.aaue
261class CustomExportPDFCourseRegistrationSlipPage(
262    NigeriaExportPDFCourseRegistrationSlipPage):
263    """Deliver a PDF slip of the context.
264    """
265    grok.context(ICustomStudentStudyLevel)
266    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
267        'level_session', 'level_verdict',
268        'validated_by', 'validation_date', 'gpa')
269
270    omit_fields = ('password', 'suspended', 'suspended_comment',
271        'phone', 'adm_code', 'sex', 'email', 'date_of_birth',
272        'department', 'current_mode', 'current_level')
273
274    @property
275    def title(self):
276        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
277        return translate(_('Credits Registered'), 'waeup.kofa',
278            target_language=portal_language)
279
280    def _signatures(self):
281        """Signatures as inserted at document bottom.
282
283        As Kwarapoly requires a fancy 'certificate' there, the pre-
284        and post-fields of signatures are quite large and unusual
285        here.
286
287        This is also a workaround, as we cannot easily insert text
288        with signature fields in documents using reportlab platypus.
289
290        The signature boxes we return here contain context infos
291        (therefore this has to be a method) and return the following
292        layout:
293
294            +-----------------------------------------+
295            | (Empty pre text)                        |
296            +-------------+---------------------------+
297            |Date         | Students Signature        |
298            +-------------+---------------------------+
299            | (Empty post text)                       |
300            +=========================================+
301            |            Certification                |
302            +-------------+---------------------------+
303            |Date         | Director Signature, etc.  |
304            +-------------+---------------------------+
305            |NOTE: This form is the ...               |
306            +-----------------------------------------+
307
308
309        """
310        return (
311            [
312                ('', _('Student\'s Signature'), ''),
313                ],
314            [((
315                    "<br/>"
316                    + "&nbsp;" * 70 +
317                    "<u><b><font size='14'>Certification</font></b></u><br/>"
318                    "<br/><b><i>"
319                    "This is to certify that "
320                    "<font size='13'>"
321                    + self.context.student.display_fullname +
322                    "</font>"
323                    " has paid the full School Fees, duly registered and "
324                    "therefore, is cleared to sit for examination in the "
325                    "courses listed above."
326                    "</i></b><br/><br/>"
327                    ),
328              "Institute Director\'s Signature and Official Stamp",
329              (
330                    "<b><u>NOTE:</u></b> This form is the property of "
331                    "Kwara State Polytechnic, it is not transferable "
332                    "and students must properly fill it, get it duly "
333                    "endorsed and present it before they can be admitted "
334                    "into Examination Venues."
335                    )), ]
336            )
337
338    def render(self):
339        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
340        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
341        Title = translate('Title', 'waeup.kofa',
342                          target_language=portal_language)
343        Cred = translate(
344            'Cred.', 'waeup.kofa', target_language=portal_language)
345        Score = translate('Score', 'waeup.kofa',
346                          target_language=portal_language)
347        Grade = translate('Grade', 'waeup.kofa',
348                          target_language=portal_language)
349        Signature = translate(_('HOD\'s Signature'), 'waeup.kwarapoly',
350            target_language=portal_language)
351        studentview = StudentBasePDFFormPage(self.context.student,
352            self.request, self.omit_fields)
353        students_utils = getUtility(IStudentsUtils)
354
355        tabledata = []
356        tableheader = []
357        for i in range(1, 7):
358            tabledata.append(sorted(
359                [value for value in self.context.values()
360                 if value.semester == i],
361                key=lambda value: str(value.semester) + value.code))
362            tableheader.append([(Code, 'code', 2.0),
363                               (Title, 'title', 7),
364                               (Cred, 'credits', 1.5),
365                               (Score, 'score', 1.4),
366                               (Grade, 'grade', 1.4),
367                               (Signature, 'dummy', 3),
368                               ])
369        topMargin = 1.5 + (self.label.count('\n') * 0.2)
370        return students_utils.renderPDF(
371            self, 'course_registration_slip.pdf',
372            self.context.student, studentview,
373            tableheader=tableheader,
374            tabledata=tabledata,
375            signatures=self._signatures(),
376            topMargin=topMargin,
377            omit_fields=self.omit_fields,
378            )
379
380
381class ExportPDFRegistrationSlipPage(grok.View):
382    """Deliver a PDF slip of the context.
383    """
384    grok.context(ICustomStudent)
385    grok.name('registration_slip.pdf')
386    grok.require('waeup.viewStudent')
387    prefix = 'form'
388    omit_fields = (
389        'suspended', 'phone',
390        'adm_code', 'suspended_comment', 'email',
391        'current_mode', 'matric_number', 'date_of_birth', 'current_level')
392    title = 'Clearance and Personal Data'
393    label = 'Profile Registration Slip'
394
395    form_fields = grok.AutoFields(ICustomStudent).select(
396        'date_of_birth', 'lga', 'nationality',
397        'perm_address', 'corr_address',
398        'marit_stat', 'sponsor_name', 'sponsor_address',
399        )
400
401    def render(self):
402        if self.context.state in (CREATED, ADMITTED,
403                                  CLEARANCE, REQUESTED, CLEARED):
404            self.flash('Not allowed.')
405            self.redirect(self.url(self.context))
406            return
407        studentview = StudentBasePDFFormPage(self.context.student,
408            self.request, self.omit_fields)
409        students_utils = getUtility(IStudentsUtils)
410        return students_utils.renderPDF(
411            self, 'registration_slip.pdf',
412            self.context.student, studentview, signatures=None,
413            omit_fields=self.omit_fields,
414            note=post_text_registration)
415
416post_text_registration = """<br /><br />
417<strong>IMPORTANT NOTICE</strong>
418<br /><br />
419This registration slip must be supplied before attendance of lectures. Note that:
420<br /><br />
4211. All fees due must be paid in full.
422<br /><br />
4232. All information required must be available on the Registration Form.
424<br /><br />
4253. The Signature of all appropriate Polytechnic Authority must be obtained.
426<br /><br />
4274. The endorsed Registration Form should be returned to the respective
428   Institutes and Administrative Offices.
429<br /><br />
4305. No student may change his subject or course of study as shown in the
431   signed Registration Form without clearance from the Admissions Office
432   and the Director of the appropriate Institute.
433<br /><br />
4346. All candidates admitted into the HND I programmes should submit the
435   photocopies of their original certificates of ND and SSCE with scratch
436   card online for clearance latest a week after the admission is offered.
437   Failure to comply with this directive may lead to the forfeiture of
438   the admission.
439<br /><br />
440<!-- image size: 229x100 pixels; ratio (2.29:1) must be kept -->
441<img src="${signature_img_path}" valign="-30"
442     height="75" width="172" />
443<br />
444M.O. Adebayo<br />
445Admission Officer<br />
446For: Registrar
447"""
448
449post_text_freshers = """
450<strong>INSTRUCTIONS TO FRESHERS</strong>
451<br /><br />
452You are hereby offered a provisional admission for the 2014/2015 session subject to the conditions that:
453<br /><br />
4541. The information given in your Application Form is correct.
455<br /><br />
4562. The original of your Credentials are presented for scrutiny.
457<br /><br />
4583. If at any time the Credentials submitted are found to be false/fake
459   or incorrect, your admission shall be withdrawn.
460<br /><br />
4614. The name by which you are admitted and registered shall remain same
462   throughout the duration of your programme.
463<br /><br />
4645. You are to fill and submit the Undertaking Form at the point of
465   registration failure which your admission will be forfeited.
466<br /><br />
4676. You will dress decently covering your nakedness at all times.
468<br /><br />
4697. Payment of school fees will be once and in full and should be by
470   Interswitch to the designated Banks. Failure to pay fees by the
471   mode mentioned above by the closing date means you have declined
472   the offer and your place will be given to another eligible
473   candidate immediately.
474<br /><br />
4758. You present a Certificate of medical fitness from the Polytechnic
476   Clinic.
477<br /><br />
4789. All indigenes of Kwara State are required to present Certificate of
479   Citizenship.
480<br /><br />
48110. The Polytechnic reserves the right to withdraw your admission at
482    any stage, if you are found to be a cultist or an expelled
483    individual from any tertiary institution.
484<br /><br />
48511. You are prepared to take up accommodation provided on the campuses
486    by the authority.
487<br /><br />
48812. There will be no refund of school fees once paid.
489<br /><br />
49013. If you accept this offer with the above stated conditions, please
491    make a photocopy of this document and return it to the Admission
492    Office immediately.
493<br /><br />
49414. You possess the entry requirement for the programme you are admitted.
495<br /><br />
496
497<!-- image size: 229x100 pixels; ratio (2.29:1) must be kept -->
498<img src="${signature_img_path}" valign="-30"
499     height="75" width="172" />
500<br />
501M.O. Adebayo<br />
502Admission Officer<br />
503For: Registrar
504"""
505# XXX: a note for <img /> tag used here (from reportlab docs):
506#   The valign attribute may be set to a css like value from "baseline", "sub",
507#   "super", "top", "text-top", "middle", "bottom", "text-bottom";
508#   the value may also be a numeric percentage or an absolute value.
509#
510# Burn this remark after reading.
Note: See TracBrowser for help on using the repository browser.