source: main/waeup.kwarapoly/branches/uli-pdfsigs/src/waeup/kwarapoly/students/browser.py @ 11884

Last change on this file since 11884 was 11884, checked in by uli, 10 years ago

Adjust signature file position/size.

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