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

Last change on this file since 17808 was 17807, checked in by Henrik Bettermann, 6 months ago

tighten up some of those allowances

  • Property svn:keywords set to Id
File size: 40.0 KB
Line 
1## $Id: browser.py 17807 2024-06-03 13:23:31Z 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    NigeriaStudentFilesUploadPage,
67    )
68from waeup.uniben.students.interfaces import (
69    ICustomStudent,
70    ICustomStudentBase,
71    ICustomStudentOnlinePayment,
72    ICustomStudentStudyCourse,
73    ICustomStudentStudyLevel,
74    ICustomUGStudentClearance,
75    ICustomPGStudentClearance,
76    ICustomStudentPersonal,
77    ICustomStudentPersonalEdit,
78    IMedicalHistory,
79    ITiship,
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        studycourse = self.context['studycourse']
556        certificate = getattr(studycourse,'certificate',None)
557        current_level = studycourse.current_level
558        end_level = certificate.end_level
559        if not self.context.current_level >= end_level:
560            form_fields = form_fields.omit('nysc')
561        return form_fields
562
563class StudyCourseCOEditFormPage(KofaEditFormPage):
564    """ Page to edit the student study course data by clearance officers.
565
566    This form page is available only in Uniben.
567    """
568    grok.context(ICustomStudentStudyCourse)
569    grok.name('edit_level')
570    grok.require('waeup.clearStudent')
571    label = _('Edit current level')
572    pnav = 4
573    form_fields = grok.AutoFields(
574        ICustomStudentStudyCourse).select('current_level')
575
576    def update(self):
577        if not (self.context.is_current and
578            self.context.student.state == REQUESTED):
579            emit_lock_message(self)
580            return
581        super(StudyCourseCOEditFormPage, self).update()
582        return
583
584    @action(_('Save'), style='primary')
585    def save(self, **data):
586        try:
587            msave(self, **data)
588        except ConstraintNotSatisfied:
589            # The selected level might not exist in certificate
590            self.flash(_('Current level not available for certificate.'))
591            return
592        #notify(grok.ObjectModifiedEvent(self.context.__parent__))
593        return
594
595class CustomStudyLevelEditFormPage(StudyLevelEditFormPage):
596    """ Page to edit the student study level data by students.
597
598    """
599    grok.template('studyleveleditpage')
600
601class CustomStudyLevelDisplayFormPage(StudyLevelDisplayFormPage):
602    """ Page to display student study levels
603    """
604    grok.template('studylevelpage')
605
606    @property
607    def view_scores_allowed(self):
608        return checkPermission('waeup.manageStudent', self.context)
609
610class CustomExportPDFCourseRegistrationSlip(
611    ExportPDFCourseRegistrationSlip):
612    """Deliver a PDF slip of the context.
613    """
614
615    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
616        'level_verdict', 'gpa', 'level', 'transcript_remark')
617
618    def update(self):
619        if self.context.student.state != REGISTERED \
620            or self.context.student.current_level != self.context.level:
621            self.flash(_('Forbidden'), type="warning")
622            self.redirect(self.url(self.context))
623
624    @property
625    def tabletitle(self):
626        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
627        tabletitle = []
628        tabletitle.append(translate(_('1st Semester Courses'), 'waeup.kofa',
629            target_language=portal_language))
630        tabletitle.append(translate(_('2nd Semester Courses'), 'waeup.kofa',
631            target_language=portal_language))
632        tabletitle.append(translate(_('Level Courses'), 'waeup.kofa',
633            target_language=portal_language))
634        tabletitle.append(translate(_('1st Trimester Courses'), 'waeup.kofa',
635            target_language=portal_language))
636        tabletitle.append(translate(_('2nd Trimester Courses'), 'waeup.kofa',
637            target_language=portal_language))
638        tabletitle.append(translate(_('3rd Trimester Courses'), 'waeup.kofa',
639            target_language=portal_language))
640        return tabletitle
641
642    def render(self):
643        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
644        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
645        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
646        Dept = translate('Dept.', 'waeup.kofa', target_language=portal_language)
647        Faculty = translate('Faculty', 'waeup.kofa', target_language=portal_language)
648        Cred = translate(_('Credits'), 'waeup.uniben', target_language=portal_language)
649        studentview = StudentBasePDFFormPage(self.context.student,
650            self.request, self.omit_fields)
651        students_utils = getUtility(IStudentsUtils)
652
653        tabledata = []
654        tableheader = []
655        for i in range(1,7):
656            tabledata.append(sorted(
657                [value for value in self.context.values() if value.semester == i],
658                key=lambda value: str(value.semester) + value.code))
659            tableheader.append([(Code,'code', 2.5),
660                             (Title,'title', 5),
661                             (Dept,'dcode', 1.5), (Faculty,'fcode', 1.5),
662                             (Cred, 'credits', 1.5),
663                             ])
664        return students_utils.renderPDF(
665            self, 'course_registration_slip.pdf',
666            self.context.student, studentview,
667            tableheader=tableheader,
668            tabledata=tabledata,
669            omit_fields=self.omit_fields
670            )
671
672class ExportPDFCourseResultSlip(ExportPDFCourseRegistrationSlip):
673    """Deliver a PDF slip of the context.
674    """
675
676    grok.name('course_result_slip.pdf')
677
678    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit('level')
679
680    @property
681    def tabletitle(self):
682        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
683        tabletitle = []
684        tabletitle.append(translate(_('1st Semester Courses'), 'waeup.kofa',
685            target_language=portal_language))
686        tabletitle.append(translate(_('2nd Semester Courses'), 'waeup.kofa',
687            target_language=portal_language))
688        tabletitle.append(translate(_('Level Courses'), 'waeup.kofa',
689            target_language=portal_language))
690        tabletitle.append(translate(_('1st Trimester Courses'), 'waeup.kofa',
691            target_language=portal_language))
692        tabletitle.append(translate(_('2nd Trimester Courses'), 'waeup.kofa',
693            target_language=portal_language))
694        tabletitle.append(translate(_('3rd Trimester Courses'), 'waeup.kofa',
695            target_language=portal_language))
696        return tabletitle
697
698    @property
699    def label(self):
700        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
701        lang = self.request.cookies.get('kofa.language', portal_language)
702        level_title = translate(self.context.level_title, 'waeup.kofa',
703            target_language=lang)
704        return translate(_('Course Result Slip'),
705            'waeup.uniben', target_language=portal_language) \
706            + ' %s' % level_title
707
708    def render(self):
709        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
710        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
711        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
712        Dept = translate('Dept.', 'waeup.kofa', target_language=portal_language)
713        Faculty = translate('Faculty', 'waeup.kofa', target_language=portal_language)
714        Cred = translate(_('Credits'), 'waeup.uniben', target_language=portal_language)
715        Grade = translate('Grade', 'waeup.kofa', target_language=portal_language)
716        studentview = StudentBasePDFFormPage(self.context.student,
717            self.request, self.omit_fields)
718        students_utils = getUtility(IStudentsUtils)
719
720        tabledata = []
721        tableheader = []
722        for i in range(1,7):
723            tabledata.append(sorted(
724                [value for value in self.context.values() if value.semester == i],
725                key=lambda value: str(value.semester) + value.code))
726            tableheader.append([(Code,'code', 2.5),
727                             (Title,'title', 5),
728                             (Dept,'dcode', 1.5), (Faculty,'fcode', 1.5),
729                             (Cred, 'credits', 1.5),
730                             (Grade, 'grade', 1.5),
731                             ])
732        return students_utils.renderPDF(
733            self, 'course_result_slip.pdf',
734            self.context.student, studentview,
735            tableheader=tableheader,
736            tabledata=tabledata,
737            omit_fields=self.omit_fields
738            )
739
740class CustomCourseTicketDisplayFormPage(CourseTicketDisplayFormPage):
741    """ Page to display course tickets
742    """
743    form_fields = grok.AutoFields(ICustomCourseTicket).omit('score')
744
745class CustomCourseTicketManageFormPage(CourseTicketManageFormPage):
746    """ Page to manage course tickets
747    """
748
749    form_fields = grok.AutoFields(ICustomCourseTicket).omit('course_category')
750    form_fields['title'].for_display = True
751    form_fields['fcode'].for_display = True
752    form_fields['dcode'].for_display = True
753    form_fields['semester'].for_display = True
754    form_fields['passmark'].for_display = True
755    form_fields['credits'].for_display = True
756    form_fields['mandatory'].for_display = False
757    form_fields['automatic'].for_display = True
758    form_fields['carry_over'].for_display = True
759    form_fields['ticket_session'].for_display = True
760
761class CustomStudentActivateView(StudentActivateView):
762    """ Activate student account
763    """
764
765    def update(self):
766        self.context.suspended = False
767        self.context.writeLogMessage(self, 'account activated')
768        history = IObjectHistory(self.context)
769        history.addMessage('Student account activated', user='undisclosed')
770        self.flash(_('Student account has been activated.'))
771        self.redirect(self.url(self.context))
772        return
773
774class CustomStudentDeactivateView(StudentDeactivateView):
775    """ Deactivate student account
776    """
777    def update(self):
778        self.context.suspended = True
779        self.context.writeLogMessage(self, 'account deactivated')
780        history = IObjectHistory(self.context)
781        history.addMessage('Student account deactivated', user='undisclosed')
782        self.flash(_('Student account has been deactivated.'))
783        self.redirect(self.url(self.context))
784        return
785
786class CustomStudyCourseTranscriptPage(StudyCourseTranscriptPage):
787    """ Page to display the student's transcript.
788    """
789#    grok.require('waeup.viewStudent')
790
791class CustomExportPDFTranscriptSlip(ExportPDFTranscriptSlip):
792    """Deliver a PDF slip of the context.
793    """
794#    grok.require('waeup.viewStudent')
795
796    def _sigsInFooter(self):
797        isStudent = getattr(
798            self.request.principal, 'user_type', None) == 'student'
799        if not isStudent and self.context.student.state in (TRANSVAL, TRANSREL):
800            return (_('D. R. (Exams & Records)'),_('Current Dean of Faculty'),)
801        return ()
802
803    #def _signatures(self):
804    #    return ([(
805    #        'Current HD<br /> D. R. (Exams & Records)<br /> '
806    #        'For: Registrar')],)
807
808    def render(self):
809        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
810        Term = translate(_('Term'), 'waeup.kofa', target_language=portal_language)
811        Code = translate(_('Code'), 'waeup.kofa', target_language=portal_language)
812        Title = translate(_('Title'), 'waeup.kofa', target_language=portal_language)
813        Cred = translate(_('Credits'), 'waeup.kofa', target_language=portal_language)
814        #Score = translate(_('Score'), 'waeup.kofa', target_language=portal_language)
815        Grade = translate(_('Grade'), 'waeup.kofa', target_language=portal_language)
816        studentview = StudentBasePDFFormPage(self.context.student,
817            self.request, self.omit_fields)
818        students_utils = getUtility(IStudentsUtils)
819
820        tableheader = [(Code,'code', 2.5),
821                         (Title,'title', 8.5),
822                         (Term, 'semester', 1.5),
823                         (Cred, 'credits', 1.5),
824                         #(Score, 'score', 1.5),
825                         (Grade, 'grade', 1.5),
826                         ]
827
828        pdfstream = students_utils.renderPDFTranscript(
829            self, 'transcript.pdf',
830            self.context.student, studentview,
831            omit_fields=self.omit_fields,
832            tableheader=tableheader,
833            signatures=self._signatures(),
834            sigs_in_footer=self._sigsInFooter(),
835            digital_sigs=self._digital_sigs(),
836            save_file=self._save_file(),
837            )
838        if not pdfstream:
839            self.redirect(self.url(self.context.student))
840            return
841        return pdfstream
842
843class CustomExportPDFBedTicketSlip(NigeriaExportPDFBedTicketSlip):
844    """Deliver a PDF slip of the context.
845    """
846    omit_fields = ('password', 'suspended', 'suspended_comment',
847        'phone', 'adm_code', 'email', 'date_of_birth', 'flash_notice')
848
849class CustomPaymentsManageFormPage(PaymentsManageFormPage):
850    """ Page to manage the student payments. This manage form page is for
851    both students and students officers. Uniben does not allow students
852    to remove any payment ticket.
853    """
854    @property
855    def manage_payments_allowed(self):
856        return checkPermission('waeup.manageStudent', self.context)
857
858class CustomAccommodationDisplayFormPage(NigeriaAccommodationDisplayFormPage):
859    """ Page to view bed tickets.
860    """
861    with_hostel_selection = True
862
863class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
864    """ Page to manage bed tickets.
865    This manage form page is for both students and students officers.
866    """
867    with_hostel_selection = True
868
869class CustomStudentBaseEditFormPage(StudentBaseEditFormPage):
870    """ View to edit student base data
871    """
872    form_fields = grok.AutoFields(ICustomStudentBase).select(
873        'email', 'phone')
874    form_fields['email'].field.required = True
875
876
877
878from zope.schema.vocabulary import SimpleVocabulary
879from zope.formlib.itemswidgets import RadioWidget
880from zope.formlib.itemswidgets import SelectWidget, DropdownWidget
881
882def CustomBooleanRadioWidget(field, request, true=_('yes'), false=_('no')):
883    vocabulary = SimpleVocabulary.fromItems( ((true, True), (false, False)) )
884    widget = RadioWidget(field, vocabulary, request)
885    widget.required = False
886    return widget
887
888class StudentMedicalHistoryEditFormPage(KofaEditFormPage):
889    """ Page to edit medical data
890    """
891    grok.context(ICustomStudent)
892    grok.name('edit_medical')
893    grok.require('waeup.handleStudent')
894    label = _('Medical Questionnaire')
895    pnav = 4
896
897    def _medicalQuestPaymentMade(self, student, session):
898        if len(student['payments']):
899            for ticket in student['payments'].values():
900                if ticket.p_state == 'paid' and \
901                    ticket.p_category == 'medical_quest' and \
902                    ticket.p_session == session:
903                    return True
904        return False
905
906    def update(self):
907        if not self._medicalQuestPaymentMade(
908            self.context, self.context.current_session):
909            self.flash('Please pay medical questionnaire payment first.',
910                type="warning")
911            self.redirect(self.url(self.context))
912            return
913        return super(StudentMedicalHistoryEditFormPage, self).update()
914
915    @property
916    def form_fields(self):
917        form_fields = grok.AutoFields(IMedicalHistory) + grok.AutoFields(ITiship)
918        form_fields['medical_updated'].for_display = True
919        for field in ('fever', 'headaches', 'catarrh', 'cough', 'sore_throat',
920                      'breathing', 'sneezing', 'weakness', 'body_pains',
921                      'smell', 'taste', 'asthma', 'hypertension', 'diabetes',
922                      'obesity', 'lagos_abuja', 'outside', 'company_suspected',
923                      'company_confirmed', 'positive', 'negative',
924                      'vaccination'):
925            form_fields[field].custom_widget = CustomBooleanRadioWidget
926        return form_fields
927
928    @property
929    def separators(self):
930        return getUtility(IStudentsUtils).SEPARATORS_DICT
931
932    @action(_('Save/Confirm'), style='primary')
933    def save(self, **data):
934        msave(self, **data)
935        self.context.medical_updated = datetime.utcnow()
936        return
937
938class StudentMedicalHistoryManageFormPage(StudentMedicalHistoryEditFormPage):
939    """ Page to manage medical data
940    """
941    grok.name('manage_medical')
942    grok.require('waeup.manageStudent')
943    label = _('Manage medical questionnaire data')
944
945    def update(self):
946        return super(StudentMedicalHistoryEditFormPage, self).update()
947
948
949class ExportPDFMedicalHistorySlip(grok.View):
950    """Deliver a PDF slip of the context.
951    """
952    grok.context(ICustomStudent)
953    grok.name('medical_questionnaire_slip.pdf')
954    grok.require('waeup.viewStudent')
955    prefix = 'form'
956    form_fields = grok.AutoFields(IMedicalHistory)
957
958    omit_fields = ('password', 'suspended', 'suspended_comment',
959                   'adm_code', 'date_of_birth',
960                   'flash_notice', 'current_mode', 'entry_mode',
961                   'entry_session', 'parents_email',
962                   'current_level', 'reg_number', 'sex',
963                   'certificate')
964
965    @property
966    def title(self):
967        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
968        return translate(_('Medical Questionnaire'), 'waeup.kofa',
969            target_language=portal_language)
970
971    @property
972    def label(self):
973        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
974        return translate(_('Medical Questionnaire Slip of'),
975            'waeup.kofa', target_language=portal_language) \
976            + ' %s' % self.context.display_fullname
977
978    def render(self):
979        studentview = StudentBasePDFFormPage(self.context.student,
980            self.request, self.omit_fields)
981        students_utils = getUtility(IStudentsUtils)
982        return students_utils.renderPDF(
983            self, 'medical_questionnaire_slip.pdf',
984            self.context.student, studentview,
985            omit_fields=self.omit_fields,)
986
987class ExportPDFTishipSlip(grok.View):
988    """Deliver a PDF slip of the context.
989    """
990    grok.context(ICustomStudent)
991    grok.name('tiship_slip.pdf')
992    grok.require('waeup.viewStudent')
993    prefix = 'form'
994    form_fields = grok.AutoFields(ITiship)
995    title = ''
996
997    omit_fields = ('password', 'suspended', 'suspended_comment',
998                   'adm_code',
999                   'flash_notice', 'current_mode', 'entry_mode',
1000                   'parents_email',
1001                   )
1002
1003    @property
1004    def label(self):
1005        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
1006        return translate(_('TISHIP Registration Slip of'),
1007            'waeup.kofa', target_language=portal_language) \
1008            + ' %s' % self.context.display_fullname
1009
1010
1011    def _sigsInFooter(self):
1012        return (_('Year of Graduation'),
1013                    _('Signature'),
1014                    _('Date'),
1015                    )
1016
1017    def render(self):
1018        studentview = StudentBasePDFFormPage(self.context.student,
1019            self.request, self.omit_fields)
1020        students_utils = getUtility(IStudentsUtils)
1021        return students_utils.renderPDF(
1022            self, 'tiship_slip.pdf',
1023            self.context.student, studentview,
1024            sigs_in_footer=self._sigsInFooter(),
1025            omit_fields=self.omit_fields,)
1026
1027class PlagTestInfoPage(KofaPage):
1028    "Landing page after plagiation test payment"
1029    grok.context(ICustomStudentOnlinePayment)
1030    grok.name('plagtestinfo')
1031    grok.require('waeup.viewStudent')
1032
1033    def update(self):
1034        if self.context.p_state != 'paid' \
1035            or self.context.p_category != 'plag_test':
1036            self.flash(_('Forbidden'), type="danger")
1037            self.redirect(self.url(self.context))
1038        return super(PlagTestInfoPage, self).update()
1039
1040    @property
1041    def facdep(self):
1042        facdepkey = "%s-%s" % (self.context.student.faccode,
1043                               self.context.student.depcode)
1044        return DEPLINKS[facdepkey]
1045
1046class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
1047    """Deliver a PDF Admission slip.
1048    """
1049
1050    @property
1051    def post_text_pt(self):
1052        datelist = self.context.history.messages[0].split()[0].split('-')
1053        creation_date = u'%s/%s/%s' % (datelist[2], datelist[1], datelist[0])
1054        return (
1055            'Your Kofa student record was created on %s. <br/><br/>'
1056            'Please Note: This admission for '
1057            'Undergraduate Part-Time and Undergraduate Sandwich is incomplete '
1058            'until you have successfully applied on the <b>JAMB CAPS PORTAL</b>.  '
1059            'Ignore this if you have completed your own <b>pre-admission</b> '
1060            'activities on the JAMB website.' % creation_date)
1061
1062    def render(self):
1063        students_utils = getUtility(IStudentsUtils)
1064        letterhead_path = os.path.join(
1065            os.path.dirname(__file__), 'static', 'letterhead_admission.jpg')
1066        if not os.path.exists(letterhead_path):
1067            letterhead_path = None
1068        if self.context.current_mode in ('ug_pt', 'ug_sw'):
1069            return students_utils.renderPDFAdmissionLetter(self,
1070                self.context.student, omit_fields=self.omit_fields,
1071                letterhead_path=letterhead_path, post_text=self.post_text_pt)
1072        return students_utils.renderPDFAdmissionLetter(self,
1073            self.context.student, omit_fields=self.omit_fields,
1074            letterhead_path=letterhead_path, post_text=None)
Note: See TracBrowser for help on using the repository browser.