source: main/waeup.uniben/trunk/src/waeup/uniben/students/browser.py @ 17835

Last change on this file since 17835 was 17835, checked in by Henrik Bettermann, 2 months ago

Improve NYSCExporter.

  • Property svn:keywords set to Id
File size: 41.8 KB
Line 
1## $Id: browser.py 17835 2024-07-08 16:05:10Z 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
20import csv
21from datetime import datetime
22from zope.i18n import translate
23from zope.security import checkPermission
24from zope.schema.interfaces import ConstraintNotSatisfied
25from zope.formlib.textwidgets import BytesDisplayWidget
26from zope.component import getUtility
27from hurry.workflow.interfaces import IWorkflowInfo
28from waeup.kofa.interfaces import (
29    REQUESTED, IExtFileStore, IKofaUtils, IObjectHistory)
30from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
31from waeup.kofa.browser.layout import action, KofaEditFormPage, UtilityView, KofaPage
32from waeup.kofa.students.browser import (
33    StudentBaseEditFormPage,
34    StudyLevelEditFormPage, StudyLevelDisplayFormPage,
35    StudentBasePDFFormPage, ExportPDFCourseRegistrationSlip,
36    CourseTicketDisplayFormPage,
37    CourseTicketManageFormPage,
38    StudentTriggerTransitionFormPage,
39    msave, emit_lock_message,
40    StudentActivateView, StudentDeactivateView,
41    ExportPDFTranscriptSlip,
42    PaymentsManageFormPage,
43    StartClearancePage,
44    StudentFilesUploadPage,
45    StudyCourseTranscriptPage,
46    ExportPDFAdmissionSlip)
47from waeup.kofa.students.workflow import (CREATED, ADMITTED, PAID,
48    CLEARANCE, REQUESTED, RETURNING, CLEARED, REGISTERED, VALIDATED,
49    GRADUATED, TRANSREQ, TRANSVAL, TRANSREL, FORBIDDEN_POSTGRAD_TRANS)
50from waeup.kofa.students.interfaces import IStudentsUtils, ICourseTicket
51from waeup.kofa.students.workflow import FORBIDDEN_POSTGRAD_TRANS
52from kofacustom.nigeria.students.browser import (
53    NigeriaOnlinePaymentDisplayFormPage,
54    NigeriaStudentBaseManageFormPage,
55    NigeriaStudentClearanceEditFormPage,
56    NigeriaOnlinePaymentAddFormPage,
57    NigeriaExportPDFPaymentSlip,
58    NigeriaExportPDFClearanceSlip,
59    NigeriaExportPDFBedTicketSlip,
60    NigeriaStudentPersonalDisplayFormPage,
61    NigeriaStudentPersonalManageFormPage,
62    NigeriaStudentPersonalEditFormPage,
63    NigeriaAccommodationManageFormPage,
64    NigeriaAccommodationDisplayFormPage,
65    NigeriaStudentBaseDisplayFormPage,
66    )
67from waeup.uniben.students.interfaces import (
68    ICustomStudent,
69    ICustomStudentBase,
70    ICustomStudentOnlinePayment,
71    ICustomStudentStudyCourse,
72    ICustomStudentStudyLevel,
73    ICustomUGStudentClearance,
74    ICustomPGStudentClearance,
75    ICustomStudentPersonal,
76    ICustomStudentPersonalEdit,
77    IMedicalHistory,
78    ITiship,
79    INYSC,
80    ICustomCourseTicket)
81from waeup.uniben.interfaces import MessageFactory as _
82
83deplinks_path = os.path.join(
84    os.path.dirname(__file__), 'deplinks.csv')
85reader = csv.DictReader(open(deplinks_path, 'rb'))
86DEPLINKS = {line['code']:line['url'] for line in reader}
87
88class CustomStudentBaseDisplayFormPage(NigeriaStudentBaseDisplayFormPage):
89    """ Page to display student base data
90    """
91    form_fields = grok.AutoFields(ICustomStudentBase).omit(
92        'password', 'suspended', 'suspended_comment',
93        'flash_notice', 'provisionally_cleared', 'parents_email')
94    form_fields[
95        'financial_clearance_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
96
97class CustomStudentBaseManageFormPage(NigeriaStudentBaseManageFormPage):
98    """ View to manage student base data
99    """
100    form_fields = grok.AutoFields(ICustomStudentBase).omit(
101        'student_id', 'adm_code', 'suspended',
102        'financially_cleared_by', 'financial_clearance_date',
103        'parents_email')
104
105class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage):
106    """ Page to view an online payment ticket
107    """
108    grok.context(ICustomStudentOnlinePayment)
109    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
110        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
111    form_fields[
112        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
113    form_fields[
114        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
115
116class CustomStartClearancePage(StartClearancePage):
117
118    @property
119    def with_ac(self):
120        if self.context.faccode == 'DCOEM':
121            return False
122        return True
123
124    @property
125    def portrait_uploaded(self):
126        return True
127
128
129CLEARANCE_FLASH_MESSAGE = """
130If you have not presented for physical clearance, scan your WAEC, NECO
131and other O level results scratch cards on one document and
132attach to the form below (Scans > O Level Results Scratch Card).
133Then come back to check for your successful cleared status as from 3 days
134after successful clearance request.
135If status is cleared, pay your school charges and proceed to the
136Dean's Office to collect the signed eligibility form.
137"""
138
139class CustomStudentClearanceEditFormPage(NigeriaStudentClearanceEditFormPage):
140    """ View to edit student clearance data by student
141    """
142
143    @property
144    def form_fields(self):
145        if self.context.is_postgrad:
146            form_fields = grok.AutoFields(ICustomPGStudentClearance).omit(
147            'clearance_locked', 'nysc_location', 'clr_code', 'officer_comment',
148            'physical_clearance_date')
149        else:
150            form_fields = grok.AutoFields(ICustomUGStudentClearance).omit(
151            'clearance_locked', 'clr_code', 'officer_comment',
152            'physical_clearance_date')
153            form_fields['date_of_birth'].for_display = True
154            form_fields['nationality'].for_display = True
155            form_fields['lga'].for_display = True
156        return form_fields
157
158    def dataNotComplete(self):
159        store = getUtility(IExtFileStore)
160        if self.context.entry_mode in ('ug_ft', 'de_ft') and \
161            not store.getFileByContext(self.context, attr=u'passport.jpg'):
162            return _('No red background passport picture uploaded.')
163        if not store.getFileByContext(self.context, attr=u'birth_certificate.jpg'):
164            return _('No birth certificate uploaded.')
165        if not store.getFileByContext(self.context, attr=u'ref_let.jpg'):
166            return _('No guarantor/referee letter uploaded.')
167        if not store.getFileByContext(self.context, attr=u'acc_let.jpg'):
168            return _('No acceptance letter uploaded.')
169        if not store.getFileByContext(self.context, attr=u'fst_sit_scan.jpg'):
170            return _('No first sitting result uploaded.')
171        if not store.getFileByContext(self.context, attr=u'secr_cults.jpg'):
172            return _('No affidavit of non-membership of secret cults uploaded.')
173        if not store.getFileByContext(self.context, attr=u'olevel_sc.jpg'):
174            return _('No O level results scratch card uploaded.')
175        return False
176
177    #def update(self):
178    #    self.flash(CLEARANCE_FLASH_MESSAGE, type="warning")
179    #    return super(CustomStudentClearanceEditFormPage, self).update()
180
181class CustomOnlinePaymentAddFormPage(NigeriaOnlinePaymentAddFormPage):
182    """ Page to add an online payment ticket
183    """
184    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).select(
185        'p_combi')
186
187class CustomExportPDFPaymentSlip(NigeriaExportPDFPaymentSlip):
188    """Deliver a PDF slip of the context.
189    """
190    grok.context(ICustomStudentOnlinePayment)
191    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
192        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item', 'p_combi')
193    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
194    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
195
196
197class CustomExportPDFClearanceSlip(NigeriaExportPDFClearanceSlip):
198    """Deliver a PDF slip of the context.
199    """
200
201    @property
202    def omit_fields(self):
203        omit_fields = ('password', 'suspended', 'suspended_comment',
204                       'phone', 'adm_code', 'email', 'date_of_birth',
205                       'flash_notice')
206        if self.context.is_jupeb:
207            omit_fields += ('faculty', 'department')
208        return omit_fields
209
210    @property
211    def label(self):
212        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
213        line0 = ''
214        if self.context.is_jupeb:
215            line0 = 'Joint Universities Preliminary Examinations Board (JUPEB)\n'
216        line1 = translate(_('Clearance Slip of'),
217            'waeup.kofa', target_language=portal_language) \
218            + ' %s' % self.context.display_fullname
219        return '%s%s' % (line0, line1)
220
221    def _sigsInFooter(self):
222        isStudent = getattr(
223            self.request.principal, 'user_type', None) == 'student'
224        if not isStudent and self.context.state in (CLEARED, RETURNING):
225            return (_('Date, Student Signature'),
226                    _('Date, Clearance Officer Signature'),
227                    )
228        return ()
229
230    def render(self):
231        studentview = StudentBasePDFFormPage(self.context.student,
232            self.request, self.omit_fields)
233        students_utils = getUtility(IStudentsUtils)
234        return students_utils.renderPDF(
235            self, 'clearance_slip.pdf',
236            self.context.student, studentview, signatures=self._signatures(),
237            sigs_in_footer=self._sigsInFooter(), show_scans=False,
238            omit_fields=self.omit_fields)
239
240
241class ExportClearanceInvitationSlip(UtilityView, grok.View):
242    """Deliver an invitation letter to physical clearance.
243
244    This form page is available only in Uniben.
245    """
246    grok.context(ICustomStudent)
247    grok.name('clearance_invitation_slip.pdf')
248    grok.require('waeup.viewStudent')
249    prefix = 'form'
250
251    label = u'Invitation Letter for Physical Clearance'
252
253    omit_fields = (
254        'suspended', 'phone', 'email',
255        'adm_code', 'suspended_comment',
256        'date_of_birth', 'current_level',
257        'department', 'current_mode',
258        'entry_session', 'matric_number', 'sex',
259        'flash_notice')
260
261    form_fields = []
262
263    @property
264    def note(self):
265        if self.context.physical_clearance_date:
266            return """
267<br /><br /><br /><br /><font size='12'>
268Dear %s,
269<br /><br /><br />
270You are invited for your Health Centre clearance on:
271<br /><br />
272<strong>%s</strong>.
273<br /><br />
274Please bring along your downloaded Health Centre Form to the University Health Centre
275on your Health Centre clearance date.
276<br /><br /><br />
277Signed,
278<br /><br />
279The Registrar<br />
280</font>
281
282""" % (self.context.display_fullname, self.context.physical_clearance_date)
283        return
284
285
286    def update(self):
287        if self.context.student.state != REQUESTED \
288            or not  self.context.student.physical_clearance_date:
289            self.flash(_('Forbidden'), type="warning")
290            self.redirect(self.url(self.context))
291
292    def render(self):
293        studentview = StudentBasePDFFormPage(self.context.student,
294            self.request, self.omit_fields)
295        students_utils = getUtility(IStudentsUtils)
296        return students_utils.renderPDF(
297            self, 'clearance_invitation_slip',
298            self.context.student, studentview,
299            omit_fields=self.omit_fields,
300            note=self.note)
301
302class ExportMedicalExaminationSlip(UtilityView, grok.View):
303    """Deliver an .
304
305    This form page is available only in Uniben.
306    """
307    grok.context(ICustomStudent)
308    grok.name('medical_examination_slip.pdf')
309    grok.require('waeup.viewStudent')
310    prefix = 'form'
311
312    label = u'Uniben Medical Examination Form'
313
314    omit_fields = (
315        'suspended',
316        'adm_code', 'suspended_comment',
317        'current_level',
318        'department', 'current_mode',
319        'entry_session', 'matric_number',
320        'flash_notice', 'parents_email',
321        'faculty', 'department')
322
323    form_fields = grok.AutoFields(ICustomStudentPersonal).select(
324        'marit_stat', 'perm_address', 'next_kin_phone')
325    form_fields['perm_address'].custom_widget = BytesDisplayWidget
326
327    def _medicalClearancePaymentMade(self, student, session):
328        if len(student['payments']):
329            for ticket in student['payments'].values():
330                if ticket.p_state == 'paid' and \
331                    ticket.p_category == 'medical_clearance' and \
332                    ticket.p_session == session:
333                    return True
334        return False
335
336    def update(self):
337        if self.context.student.state != CLEARED \
338            or not  self.context.student.physical_clearance_date:
339            self.flash(_('Forbidden'), type="warning")
340            self.redirect(self.url(self.context))
341        if not self._medicalClearancePaymentMade(
342            self.context, self.context.current_session):
343            self.flash('Please pay medical clearance fee first.',
344                type="warning")
345            self.redirect(self.url(self.context))
346        return
347
348    def render(self):
349        studentview = StudentBasePDFFormPage(self.context.student,
350            self.request, self.omit_fields)
351        students_utils = getUtility(IStudentsUtils)
352        file_path = os.path.join(
353            os.path.dirname(__file__), 'static', 'medical_examination_form.pdf')
354        file = open(file_path, 'rb')
355        mergefiles = [file,]
356        return students_utils.renderPDF(
357            self, 'medical_examination_slip',
358            self.context.student, studentview,
359            omit_fields=self.omit_fields,
360            mergefiles=mergefiles,
361            )
362
363
364class ExportExaminationScheduleSlip(UtilityView, grok.View):
365    """Deliver a examination schedule slip.
366
367    This form page is available only in Uniben and AAUE.
368    """
369    grok.context(ICustomStudent)
370    grok.name('examination_schedule_slip.pdf')
371    grok.require('waeup.viewStudent')
372    prefix = 'form'
373
374    label = u'Examination Schedule Slip'
375
376    omit_fields = (
377        'suspended', 'phone', 'email',
378        'adm_code', 'suspended_comment',
379        'date_of_birth', 'current_level',
380        'current_mode',
381        'entry_session',
382        'flash_notice')
383
384    form_fields = []
385
386    @property
387    def note(self):
388        return """
389<br /><br /><br /><br /><font size='12'>
390Your examination date, time and venue is scheduled as follows:
391<br /><br />
392<strong>%s</strong>
393</font>
394
395""" % self.context.flash_notice
396        return
397
398
399    def update(self):
400        if not self.context.flash_notice \
401            or not 'exam' in self.context.flash_notice.lower():
402            self.flash(_('Forbidden'), type="warning")
403            self.redirect(self.url(self.context))
404
405    def render(self):
406        studentview = StudentBasePDFFormPage(self.context.student,
407            self.request, self.omit_fields)
408        students_utils = getUtility(IStudentsUtils)
409        return students_utils.renderPDF(
410            self, 'examination_schedule_slip',
411            self.context.student, studentview,
412            omit_fields=self.omit_fields,
413            note=self.note)
414
415class SwitchLibraryAccessView(UtilityView, grok.View):
416    """ Switch the library attribute
417    """
418    grok.context(ICustomStudent)
419    grok.name('switch_library_access')
420    grok.require('waeup.switchLibraryAccess')
421
422    def update(self):
423        if self.context.library:
424            self.context.library = False
425            self.context.writeLogMessage(self, 'library access disabled')
426            self.flash(_('Library access disabled'))
427        else:
428            self.context.library = True
429            self.context.writeLogMessage(self, 'library access enabled')
430            self.flash(_('Library access enabled'))
431        self.redirect(self.url(self.context))
432        return
433
434    def render(self):
435        return
436
437class ExportJHLIdCard(UtilityView, grok.View):
438    """Deliver an id card for the John Harris Library.
439    """
440    grok.context(ICustomStudent)
441    grok.name('jhl_idcard.pdf')
442    grok.require('waeup.viewStudent')
443    prefix = 'form'
444
445    label = u"John Harris Library Clearance"
446
447    omit_fields = (
448        'suspended', 'email', 'phone',
449        'adm_code', 'suspended_comment',
450        'date_of_birth',
451        'current_mode', 'certificate',
452        'entry_session',
453        'flash_notice')
454
455    form_fields = []
456
457    def _sigsInFooter(self):
458        isStudent = getattr(
459            self.request.principal, 'user_type', None) == 'student'
460        if isStudent:
461            return ''
462        return (_("Date, Reader's Signature"),
463                _("Date, Circulation Librarian's Signature"),
464                )
465
466    def update(self):
467        if not self.context.library:
468            self.flash(_('Forbidden!'), type="danger")
469            self.redirect(self.url(self.context))
470        return
471
472    @property
473    def note(self):
474        return """
475<br /><br /><br /><br /><font size='12'>
476This is to certify that the bearer whose photograph and other details appear
477 overleaf is a registered user of <b>John Harris Library, University of Benin</b>.
478 The card is not transferable. A replacement fee is charged for a loss,
479 mutilation or otherwise. If found, please, return to John Harris Library,
480 University of Benin, Benin City.
481</font>
482
483"""
484        return
485
486    def render(self):
487        studentview = StudentBasePDFFormPage(self.context.student,
488            self.request, self.omit_fields)
489        students_utils = getUtility(IStudentsUtils)
490        return students_utils.renderPDF(
491            self, 'jhl_idcard',
492            self.context.student, studentview,
493            omit_fields=self.omit_fields,
494            sigs_in_footer=self._sigsInFooter(),
495            note=self.note)
496
497class ExportJUPEBResultSlip(ExportExaminationScheduleSlip):
498    """Deliver a JUPEB result slip.
499
500    This form page is available only in Uniben.
501    """
502
503    grok.name('jupeb_result_slip.pdf')
504    label = u'JUPEB Result Slip'
505
506    @property
507    def note(self):
508        return """
509<br /><br /><br /><br /><font size='12'>
510<strong>%s</strong>
511</font>
512<br /><br /><br /><br />
513<font size='8'>
514Key: A = 5, B = 4, C = 3, D = 2, E = 1, F = 0, X = Absent, Q = Cancelled
515</font>
516
517""" % self.context.flash_notice
518        return
519
520    def update(self):
521        if not self.context.flash_notice or not self.context.is_jupeb \
522            or not 'results' in self.context.flash_notice.lower():
523            self.flash(_('Forbidden'), type="warning")
524            self.redirect(self.url(self.context))
525
526class CustomStudentPersonalDisplayFormPage(
527    NigeriaStudentPersonalDisplayFormPage):
528    """ Page to display student personal data
529    """
530
531    form_fields = grok.AutoFields(ICustomStudentPersonal) + grok.AutoFields(ITiship)
532    form_fields['perm_address'].custom_widget = BytesDisplayWidget
533    form_fields['next_kin_address'].custom_widget = BytesDisplayWidget
534    form_fields[
535        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
536
537class CustomStudentPersonalManageFormPage(
538    NigeriaStudentPersonalManageFormPage):
539    """ Page to manage personal data
540    """
541
542    form_fields = grok.AutoFields(ICustomStudentPersonal) + grok.AutoFields(ITiship)
543    form_fields['personal_updated'].for_display = True
544    form_fields[
545        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
546
547class CstomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage):
548    """ Page to edit personal data
549    """
550
551    @property
552    def form_fields(self):
553        form_fields = grok.AutoFields(
554            ICustomStudentPersonalEdit).omit('personal_updated') + grok.AutoFields(ITiship)
555        return form_fields
556
557class StudyCourseCOEditFormPage(KofaEditFormPage):
558    """ Page to edit the student study course data by clearance officers.
559
560    This form page is available only in Uniben.
561    """
562    grok.context(ICustomStudentStudyCourse)
563    grok.name('edit_level')
564    grok.require('waeup.clearStudent')
565    label = _('Edit current level')
566    pnav = 4
567    form_fields = grok.AutoFields(
568        ICustomStudentStudyCourse).select('current_level')
569
570    def update(self):
571        if not (self.context.is_current and
572            self.context.student.state == REQUESTED):
573            emit_lock_message(self)
574            return
575        super(StudyCourseCOEditFormPage, self).update()
576        return
577
578    @action(_('Save'), style='primary')
579    def save(self, **data):
580        try:
581            msave(self, **data)
582        except ConstraintNotSatisfied:
583            # The selected level might not exist in certificate
584            self.flash(_('Current level not available for certificate.'))
585            return
586        #notify(grok.ObjectModifiedEvent(self.context.__parent__))
587        return
588
589class CustomStudyLevelEditFormPage(StudyLevelEditFormPage):
590    """ Page to edit the student study level data by students.
591
592    """
593    grok.template('studyleveleditpage')
594
595class CustomStudyLevelDisplayFormPage(StudyLevelDisplayFormPage):
596    """ Page to display student study levels
597    """
598    grok.template('studylevelpage')
599
600    @property
601    def view_scores_allowed(self):
602        return checkPermission('waeup.manageStudent', self.context)
603
604class CustomExportPDFCourseRegistrationSlip(
605    ExportPDFCourseRegistrationSlip):
606    """Deliver a PDF slip of the context.
607    """
608
609    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
610        'level_verdict', 'gpa', 'level', 'transcript_remark')
611
612    def update(self):
613        if self.context.student.state != REGISTERED \
614            or self.context.student.current_level != self.context.level:
615            self.flash(_('Forbidden'), type="warning")
616            self.redirect(self.url(self.context))
617
618    @property
619    def tabletitle(self):
620        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
621        tabletitle = []
622        tabletitle.append(translate(_('1st Semester Courses'), 'waeup.kofa',
623            target_language=portal_language))
624        tabletitle.append(translate(_('2nd Semester Courses'), 'waeup.kofa',
625            target_language=portal_language))
626        tabletitle.append(translate(_('Level Courses'), 'waeup.kofa',
627            target_language=portal_language))
628        tabletitle.append(translate(_('1st Trimester Courses'), 'waeup.kofa',
629            target_language=portal_language))
630        tabletitle.append(translate(_('2nd Trimester Courses'), 'waeup.kofa',
631            target_language=portal_language))
632        tabletitle.append(translate(_('3rd Trimester Courses'), 'waeup.kofa',
633            target_language=portal_language))
634        return tabletitle
635
636    def render(self):
637        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
638        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
639        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
640        Dept = translate('Dept.', 'waeup.kofa', target_language=portal_language)
641        Faculty = translate('Faculty', 'waeup.kofa', target_language=portal_language)
642        Cred = translate(_('Credits'), 'waeup.uniben', target_language=portal_language)
643        studentview = StudentBasePDFFormPage(self.context.student,
644            self.request, self.omit_fields)
645        students_utils = getUtility(IStudentsUtils)
646
647        tabledata = []
648        tableheader = []
649        for i in range(1,7):
650            tabledata.append(sorted(
651                [value for value in self.context.values() if value.semester == i],
652                key=lambda value: str(value.semester) + value.code))
653            tableheader.append([(Code,'code', 2.5),
654                             (Title,'title', 5),
655                             (Dept,'dcode', 1.5), (Faculty,'fcode', 1.5),
656                             (Cred, 'credits', 1.5),
657                             ])
658        return students_utils.renderPDF(
659            self, 'course_registration_slip.pdf',
660            self.context.student, studentview,
661            tableheader=tableheader,
662            tabledata=tabledata,
663            omit_fields=self.omit_fields
664            )
665
666class ExportPDFCourseResultSlip(ExportPDFCourseRegistrationSlip):
667    """Deliver a PDF slip of the context.
668    """
669
670    grok.name('course_result_slip.pdf')
671
672    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit('level')
673
674    @property
675    def tabletitle(self):
676        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
677        tabletitle = []
678        tabletitle.append(translate(_('1st Semester Courses'), 'waeup.kofa',
679            target_language=portal_language))
680        tabletitle.append(translate(_('2nd Semester Courses'), 'waeup.kofa',
681            target_language=portal_language))
682        tabletitle.append(translate(_('Level Courses'), 'waeup.kofa',
683            target_language=portal_language))
684        tabletitle.append(translate(_('1st Trimester Courses'), 'waeup.kofa',
685            target_language=portal_language))
686        tabletitle.append(translate(_('2nd Trimester Courses'), 'waeup.kofa',
687            target_language=portal_language))
688        tabletitle.append(translate(_('3rd Trimester Courses'), 'waeup.kofa',
689            target_language=portal_language))
690        return tabletitle
691
692    @property
693    def label(self):
694        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
695        lang = self.request.cookies.get('kofa.language', portal_language)
696        level_title = translate(self.context.level_title, 'waeup.kofa',
697            target_language=lang)
698        return translate(_('Course Result Slip'),
699            'waeup.uniben', target_language=portal_language) \
700            + ' %s' % level_title
701
702    def render(self):
703        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
704        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
705        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
706        Dept = translate('Dept.', 'waeup.kofa', target_language=portal_language)
707        Faculty = translate('Faculty', 'waeup.kofa', target_language=portal_language)
708        Cred = translate(_('Credits'), 'waeup.uniben', target_language=portal_language)
709        Grade = translate('Grade', 'waeup.kofa', target_language=portal_language)
710        studentview = StudentBasePDFFormPage(self.context.student,
711            self.request, self.omit_fields)
712        students_utils = getUtility(IStudentsUtils)
713
714        tabledata = []
715        tableheader = []
716        for i in range(1,7):
717            tabledata.append(sorted(
718                [value for value in self.context.values() if value.semester == i],
719                key=lambda value: str(value.semester) + value.code))
720            tableheader.append([(Code,'code', 2.5),
721                             (Title,'title', 5),
722                             (Dept,'dcode', 1.5), (Faculty,'fcode', 1.5),
723                             (Cred, 'credits', 1.5),
724                             (Grade, 'grade', 1.5),
725                             ])
726        return students_utils.renderPDF(
727            self, 'course_result_slip.pdf',
728            self.context.student, studentview,
729            tableheader=tableheader,
730            tabledata=tabledata,
731            omit_fields=self.omit_fields
732            )
733
734class CustomCourseTicketDisplayFormPage(CourseTicketDisplayFormPage):
735    """ Page to display course tickets
736    """
737    form_fields = grok.AutoFields(ICustomCourseTicket).omit('score')
738
739class CustomCourseTicketManageFormPage(CourseTicketManageFormPage):
740    """ Page to manage course tickets
741    """
742
743    form_fields = grok.AutoFields(ICustomCourseTicket).omit('course_category')
744    form_fields['title'].for_display = True
745    form_fields['fcode'].for_display = True
746    form_fields['dcode'].for_display = True
747    form_fields['semester'].for_display = True
748    form_fields['passmark'].for_display = True
749    form_fields['credits'].for_display = True
750    form_fields['mandatory'].for_display = False
751    form_fields['automatic'].for_display = True
752    form_fields['carry_over'].for_display = True
753    form_fields['ticket_session'].for_display = True
754
755class CustomStudentActivateView(StudentActivateView):
756    """ Activate student account
757    """
758
759    def update(self):
760        self.context.suspended = False
761        self.context.writeLogMessage(self, 'account activated')
762        history = IObjectHistory(self.context)
763        history.addMessage('Student account activated', user='undisclosed')
764        self.flash(_('Student account has been activated.'))
765        self.redirect(self.url(self.context))
766        return
767
768class CustomStudentDeactivateView(StudentDeactivateView):
769    """ Deactivate student account
770    """
771    def update(self):
772        self.context.suspended = True
773        self.context.writeLogMessage(self, 'account deactivated')
774        history = IObjectHistory(self.context)
775        history.addMessage('Student account deactivated', user='undisclosed')
776        self.flash(_('Student account has been deactivated.'))
777        self.redirect(self.url(self.context))
778        return
779
780class CustomStudyCourseTranscriptPage(StudyCourseTranscriptPage):
781    """ Page to display the student's transcript.
782    """
783#    grok.require('waeup.viewStudent')
784
785class CustomExportPDFTranscriptSlip(ExportPDFTranscriptSlip):
786    """Deliver a PDF slip of the context.
787    """
788#    grok.require('waeup.viewStudent')
789
790    def _sigsInFooter(self):
791        isStudent = getattr(
792            self.request.principal, 'user_type', None) == 'student'
793        if not isStudent and self.context.student.state in (TRANSVAL, TRANSREL):
794            return (_('D. R. (Exams & Records)'),_('Current Dean of Faculty'),)
795        return ()
796
797    #def _signatures(self):
798    #    return ([(
799    #        'Current HD<br /> D. R. (Exams & Records)<br /> '
800    #        'For: Registrar')],)
801
802    def render(self):
803        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
804        Term = translate(_('Term'), 'waeup.kofa', target_language=portal_language)
805        Code = translate(_('Code'), 'waeup.kofa', target_language=portal_language)
806        Title = translate(_('Title'), 'waeup.kofa', target_language=portal_language)
807        Cred = translate(_('Credits'), 'waeup.kofa', target_language=portal_language)
808        #Score = translate(_('Score'), 'waeup.kofa', target_language=portal_language)
809        Grade = translate(_('Grade'), 'waeup.kofa', target_language=portal_language)
810        studentview = StudentBasePDFFormPage(self.context.student,
811            self.request, self.omit_fields)
812        students_utils = getUtility(IStudentsUtils)
813
814        tableheader = [(Code,'code', 2.5),
815                         (Title,'title', 8.5),
816                         (Term, 'semester', 1.5),
817                         (Cred, 'credits', 1.5),
818                         #(Score, 'score', 1.5),
819                         (Grade, 'grade', 1.5),
820                         ]
821
822        pdfstream = students_utils.renderPDFTranscript(
823            self, 'transcript.pdf',
824            self.context.student, studentview,
825            omit_fields=self.omit_fields,
826            tableheader=tableheader,
827            signatures=self._signatures(),
828            sigs_in_footer=self._sigsInFooter(),
829            digital_sigs=self._digital_sigs(),
830            save_file=self._save_file(),
831            )
832        if not pdfstream:
833            self.redirect(self.url(self.context.student))
834            return
835        return pdfstream
836
837class CustomExportPDFBedTicketSlip(NigeriaExportPDFBedTicketSlip):
838    """Deliver a PDF slip of the context.
839    """
840    omit_fields = ('password', 'suspended', 'suspended_comment',
841        'phone', 'adm_code', 'email', 'date_of_birth', 'flash_notice')
842
843class CustomPaymentsManageFormPage(PaymentsManageFormPage):
844    """ Page to manage the student payments. This manage form page is for
845    both students and students officers. Uniben does not allow students
846    to remove any payment ticket.
847    """
848    @property
849    def manage_payments_allowed(self):
850        return checkPermission('waeup.manageStudent', self.context)
851
852class CustomAccommodationDisplayFormPage(NigeriaAccommodationDisplayFormPage):
853    """ Page to view bed tickets.
854    """
855    with_hostel_selection = True
856
857class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
858    """ Page to manage bed tickets.
859    This manage form page is for both students and students officers.
860    """
861    with_hostel_selection = True
862
863class CustomStudentBaseEditFormPage(StudentBaseEditFormPage):
864    """ View to edit student base data
865    """
866    form_fields = grok.AutoFields(ICustomStudentBase).select(
867        'email', 'phone')
868    form_fields['email'].field.required = True
869
870
871
872from zope.schema.vocabulary import SimpleVocabulary
873from zope.formlib.itemswidgets import RadioWidget
874from zope.formlib.itemswidgets import SelectWidget, DropdownWidget
875
876def CustomBooleanRadioWidget(field, request, true=_('yes'), false=_('no')):
877    vocabulary = SimpleVocabulary.fromItems( ((true, True), (false, False)) )
878    widget = RadioWidget(field, vocabulary, request)
879    widget.required = False
880    return widget
881
882class StudentMedicalHistoryEditFormPage(KofaEditFormPage):
883    """ Page to edit medical data
884    """
885    grok.context(ICustomStudent)
886    grok.name('edit_medical')
887    grok.require('waeup.handleStudent')
888    label = _('Medical Questionnaire')
889    pnav = 4
890
891    def _medicalQuestPaymentMade(self, student, session):
892        if len(student['payments']):
893            for ticket in student['payments'].values():
894                if ticket.p_state == 'paid' and \
895                    ticket.p_category == 'medical_quest' and \
896                    ticket.p_session == session:
897                    return True
898        return False
899
900    def update(self):
901        if not self._medicalQuestPaymentMade(
902            self.context, self.context.current_session):
903            self.flash('Please pay medical questionnaire payment first.',
904                type="warning")
905            self.redirect(self.url(self.context))
906            return
907        return super(StudentMedicalHistoryEditFormPage, self).update()
908
909    @property
910    def form_fields(self):
911        form_fields = grok.AutoFields(IMedicalHistory) + grok.AutoFields(ITiship)
912        form_fields['medical_updated'].for_display = True
913        for field in ('fever', 'headaches', 'catarrh', 'cough', 'sore_throat',
914                      'breathing', 'sneezing', 'weakness', 'body_pains',
915                      'smell', 'taste', 'asthma', 'hypertension', 'diabetes',
916                      'obesity', 'lagos_abuja', 'outside', 'company_suspected',
917                      'company_confirmed', 'positive', 'negative',
918                      'vaccination'):
919            form_fields[field].custom_widget = CustomBooleanRadioWidget
920        return form_fields
921
922    @property
923    def separators(self):
924        return getUtility(IStudentsUtils).SEPARATORS_DICT
925
926    @action(_('Save/Confirm'), style='primary')
927    def save(self, **data):
928        msave(self, **data)
929        self.context.medical_updated = datetime.utcnow()
930        return
931
932class StudentMedicalHistoryManageFormPage(StudentMedicalHistoryEditFormPage):
933    """ Page to manage medical data
934    """
935    grok.name('manage_medical')
936    grok.require('waeup.manageStudent')
937    label = _('Manage medical questionnaire data')
938
939    def update(self):
940        return super(StudentMedicalHistoryEditFormPage, self).update()
941
942
943class ExportPDFMedicalHistorySlip(grok.View):
944    """Deliver a PDF slip of the context.
945    """
946    grok.context(ICustomStudent)
947    grok.name('medical_questionnaire_slip.pdf')
948    grok.require('waeup.viewStudent')
949    prefix = 'form'
950    form_fields = grok.AutoFields(IMedicalHistory)
951
952    omit_fields = ('password', 'suspended', 'suspended_comment',
953                   'adm_code', 'date_of_birth',
954                   'flash_notice', 'current_mode', 'entry_mode',
955                   'entry_session', 'parents_email',
956                   'current_level', 'reg_number', 'sex',
957                   'certificate')
958
959    @property
960    def title(self):
961        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
962        return translate(_('Medical Questionnaire'), 'waeup.kofa',
963            target_language=portal_language)
964
965    @property
966    def label(self):
967        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
968        return translate(_('Medical Questionnaire Slip of'),
969            'waeup.kofa', target_language=portal_language) \
970            + ' %s' % self.context.display_fullname
971
972    def render(self):
973        studentview = StudentBasePDFFormPage(self.context.student,
974            self.request, self.omit_fields)
975        students_utils = getUtility(IStudentsUtils)
976        return students_utils.renderPDF(
977            self, 'medical_questionnaire_slip.pdf',
978            self.context.student, studentview,
979            omit_fields=self.omit_fields,)
980
981class ExportPDFTishipSlip(grok.View):
982    """Deliver a PDF slip of the context.
983    """
984    grok.context(ICustomStudent)
985    grok.name('tiship_slip.pdf')
986    grok.require('waeup.viewStudent')
987    prefix = 'form'
988    form_fields = grok.AutoFields(ITiship)
989    title = ''
990
991    omit_fields = ('password', 'suspended', 'suspended_comment',
992                   'adm_code',
993                   'flash_notice', 'current_mode', 'entry_mode',
994                   'parents_email',
995                   )
996
997    @property
998    def label(self):
999        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
1000        return translate(_('TISHIP Registration Slip of'),
1001            'waeup.kofa', target_language=portal_language) \
1002            + ' %s' % self.context.display_fullname
1003
1004
1005    def _sigsInFooter(self):
1006        return (_('Year of Graduation'),
1007                    _('Signature'),
1008                    _('Date'),
1009                    )
1010
1011    def render(self):
1012        studentview = StudentBasePDFFormPage(self.context.student,
1013            self.request, self.omit_fields)
1014        students_utils = getUtility(IStudentsUtils)
1015        return students_utils.renderPDF(
1016            self, 'tiship_slip.pdf',
1017            self.context.student, studentview,
1018            sigs_in_footer=self._sigsInFooter(),
1019            omit_fields=self.omit_fields,)
1020
1021class PlagTestInfoPage(KofaPage):
1022    "Landing page after plagiation test payment"
1023    grok.context(ICustomStudentOnlinePayment)
1024    grok.name('plagtestinfo')
1025    grok.require('waeup.viewStudent')
1026
1027    def update(self):
1028        if self.context.p_state != 'paid' \
1029            or self.context.p_category != 'plag_test':
1030            self.flash(_('Forbidden'), type="danger")
1031            self.redirect(self.url(self.context))
1032        return super(PlagTestInfoPage, self).update()
1033
1034    @property
1035    def facdep(self):
1036        facdepkey = "%s-%s" % (self.context.student.faccode,
1037                               self.context.student.depcode)
1038        return DEPLINKS[facdepkey]
1039
1040class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
1041    """Deliver a PDF Admission slip.
1042    """
1043
1044    @property
1045    def post_text_pt(self):
1046        datelist = self.context.history.messages[0].split()[0].split('-')
1047        creation_date = u'%s/%s/%s' % (datelist[2], datelist[1], datelist[0])
1048        return (
1049            'Your Kofa student record was created on %s. <br/><br/>'
1050            'Please Note: This admission for '
1051            'Undergraduate Part-Time and Undergraduate Sandwich is incomplete '
1052            'until you have successfully applied on the <b>JAMB CAPS PORTAL</b>.  '
1053            'Ignore this if you have completed your own <b>pre-admission</b> '
1054            'activities on the JAMB website.' % creation_date)
1055
1056    def render(self):
1057        students_utils = getUtility(IStudentsUtils)
1058        letterhead_path = os.path.join(
1059            os.path.dirname(__file__), 'static', 'letterhead_admission.jpg')
1060        if not os.path.exists(letterhead_path):
1061            letterhead_path = None
1062        if self.context.current_mode in ('ug_pt', 'ug_sw'):
1063            return students_utils.renderPDFAdmissionLetter(self,
1064                self.context.student, omit_fields=self.omit_fields,
1065                letterhead_path=letterhead_path, post_text=self.post_text_pt)
1066        return students_utils.renderPDFAdmissionLetter(self,
1067            self.context.student, omit_fields=self.omit_fields,
1068            letterhead_path=letterhead_path, post_text=None)
1069
1070class StudentNYSCEditFormPage(KofaEditFormPage):
1071    """ Page to edit NYSC data
1072    """
1073    grok.context(ICustomStudent)
1074    grok.name('edit_nysc')
1075    grok.require('waeup.handleStudent')
1076    label = _('NYSC Request')
1077    pnav = 4
1078
1079    def update(self):
1080        if not self.context.eligible_for_nysc:
1081            self.flash('You are not allowed to apply for NYSC.',
1082                type="warning")
1083            self.redirect(self.url(self.context))
1084            return
1085        return super(StudentNYSCEditFormPage, self).update()
1086
1087    @property
1088    def form_fields(self):
1089        form_fields = grok.AutoFields(INYSC)
1090        form_fields['nysc_updated'].for_display = True
1091        #form_fields['nysc_senate_info'].for_display = True
1092        form_fields['nysc'].field.description = u'Ensure that all your school charges are paid up to date to your graduating session before making this nysc application.'
1093        form_fields['nysc'].field.title = u'Do you want to apply for NYSC?'
1094        form_fields[
1095            'nysc_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
1096        form_fields['nysc'].custom_widget = CustomBooleanRadioWidget
1097        form_fields['nysc_processed'].for_display = True
1098        #form_fields['nysc_senate_info'].field.description = u''
1099        return form_fields
1100
1101    @action(_('Save'), style='primary')
1102    def save(self, **data):
1103        msave(self, **data)
1104        self.context.nysc_updated = datetime.utcnow()
1105        return
1106
1107class StudentNYSCManageFormPage(KofaEditFormPage):
1108    """ Page to manage NYSC data
1109    """
1110    grok.context(ICustomStudent)
1111    grok.name('manage_nysc')
1112    grok.require('waeup.manageStudent')
1113    label = _('Manage NYSC request data')
1114
1115    @property
1116    def form_fields(self):
1117        form_fields = grok.AutoFields(INYSC)
1118        form_fields['nysc_updated'].for_display = True
1119        form_fields['nysc'].field.description = u''
1120        form_fields['nysc'].field.title = u'NYSC requested'
1121        form_fields[
1122            'nysc_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
1123        return form_fields
1124
1125    @action(_('Save'), style='primary')
1126    def save(self, **data):
1127        msave(self, **data)
1128        return
Note: See TracBrowser for help on using the repository browser.