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

Last change on this file since 14070 was 13714, checked in by Henrik Bettermann, 9 years ago

Hide flash_notice on slips.

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