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

Last change on this file since 17750 was 17750, checked in by Henrik Bettermann, 5 months ago

Configure deplinks via a csv file.

  • Property svn:keywords set to Id
File size: 40.4 KB
Line 
1## $Id: browser.py 17750 2024-05-06 07:53:03Z 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
876class CustomStudentFilesUploadPage(NigeriaStudentFilesUploadPage):
877    """ View to upload passport picture.
878    """
879
880    def update(self):
881        # Postgrad students should allowed to change their picture whenever they want.
882        if self.context.is_postgrad:
883            return
884        if self.context.is_jupeb:
885            emit_lock_message(self)
886            return           
887        super(StudentFilesUploadPage, self).update()
888        return
889
890
891
892from zope.schema.vocabulary import SimpleVocabulary
893from zope.formlib.itemswidgets import RadioWidget
894from zope.formlib.itemswidgets import SelectWidget, DropdownWidget
895
896def CustomBooleanRadioWidget(field, request, true=_('yes'), false=_('no')):
897    vocabulary = SimpleVocabulary.fromItems( ((true, True), (false, False)) )
898    widget = RadioWidget(field, vocabulary, request)
899    widget.required = False
900    return widget
901
902class StudentMedicalHistoryEditFormPage(KofaEditFormPage):
903    """ Page to edit medical data
904    """
905    grok.context(ICustomStudent)
906    grok.name('edit_medical')
907    grok.require('waeup.handleStudent')
908    label = _('Medical Questionnaire')
909    pnav = 4
910
911    def _medicalQuestPaymentMade(self, student, session):
912        if len(student['payments']):
913            for ticket in student['payments'].values():
914                if ticket.p_state == 'paid' and \
915                    ticket.p_category == 'medical_quest' and \
916                    ticket.p_session == session:
917                    return True
918        return False
919
920    def update(self):
921        if not self._medicalQuestPaymentMade(
922            self.context, self.context.current_session):
923            self.flash('Please pay medical questionnaire payment first.',
924                type="warning")
925            self.redirect(self.url(self.context))
926            return
927        return super(StudentMedicalHistoryEditFormPage, self).update()
928
929    @property
930    def form_fields(self):
931        form_fields = grok.AutoFields(IMedicalHistory) + grok.AutoFields(ITiship)
932        form_fields['medical_updated'].for_display = True
933        for field in ('fever', 'headaches', 'catarrh', 'cough', 'sore_throat',
934                      'breathing', 'sneezing', 'weakness', 'body_pains',
935                      'smell', 'taste', 'asthma', 'hypertension', 'diabetes',
936                      'obesity', 'lagos_abuja', 'outside', 'company_suspected',
937                      'company_confirmed', 'positive', 'negative',
938                      'vaccination'):
939            form_fields[field].custom_widget = CustomBooleanRadioWidget
940        return form_fields
941
942    @property
943    def separators(self):
944        return getUtility(IStudentsUtils).SEPARATORS_DICT
945
946    @action(_('Save/Confirm'), style='primary')
947    def save(self, **data):
948        msave(self, **data)
949        self.context.medical_updated = datetime.utcnow()
950        return
951
952class StudentMedicalHistoryManageFormPage(StudentMedicalHistoryEditFormPage):
953    """ Page to manage medical data
954    """
955    grok.name('manage_medical')
956    grok.require('waeup.manageStudent')
957    label = _('Manage medical questionnaire data')
958
959    def update(self):
960        return super(StudentMedicalHistoryEditFormPage, self).update()
961
962
963class ExportPDFMedicalHistorySlip(grok.View):
964    """Deliver a PDF slip of the context.
965    """
966    grok.context(ICustomStudent)
967    grok.name('medical_questionnaire_slip.pdf')
968    grok.require('waeup.viewStudent')
969    prefix = 'form'
970    form_fields = grok.AutoFields(IMedicalHistory)
971
972    omit_fields = ('password', 'suspended', 'suspended_comment',
973                   'adm_code', 'date_of_birth',
974                   'flash_notice', 'current_mode', 'entry_mode',
975                   'entry_session', 'parents_email',
976                   'current_level', 'reg_number', 'sex',
977                   'certificate')
978
979    @property
980    def title(self):
981        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
982        return translate(_('Medical Questionnaire'), 'waeup.kofa',
983            target_language=portal_language)
984
985    @property
986    def label(self):
987        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
988        return translate(_('Medical Questionnaire Slip of'),
989            'waeup.kofa', target_language=portal_language) \
990            + ' %s' % self.context.display_fullname
991
992    def render(self):
993        studentview = StudentBasePDFFormPage(self.context.student,
994            self.request, self.omit_fields)
995        students_utils = getUtility(IStudentsUtils)
996        return students_utils.renderPDF(
997            self, 'medical_questionnaire_slip.pdf',
998            self.context.student, studentview,
999            omit_fields=self.omit_fields,)
1000
1001class ExportPDFTishipSlip(grok.View):
1002    """Deliver a PDF slip of the context.
1003    """
1004    grok.context(ICustomStudent)
1005    grok.name('tiship_slip.pdf')
1006    grok.require('waeup.viewStudent')
1007    prefix = 'form'
1008    form_fields = grok.AutoFields(ITiship)
1009    title = ''
1010
1011    omit_fields = ('password', 'suspended', 'suspended_comment',
1012                   'adm_code',
1013                   'flash_notice', 'current_mode', 'entry_mode',
1014                   'parents_email',
1015                   )
1016
1017    @property
1018    def label(self):
1019        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
1020        return translate(_('TISHIP Registration Slip of'),
1021            'waeup.kofa', target_language=portal_language) \
1022            + ' %s' % self.context.display_fullname
1023
1024
1025    def _sigsInFooter(self):
1026        return (_('Year of Graduation'),
1027                    _('Signature'),
1028                    _('Date'),
1029                    )
1030
1031    def render(self):
1032        studentview = StudentBasePDFFormPage(self.context.student,
1033            self.request, self.omit_fields)
1034        students_utils = getUtility(IStudentsUtils)
1035        return students_utils.renderPDF(
1036            self, 'tiship_slip.pdf',
1037            self.context.student, studentview,
1038            sigs_in_footer=self._sigsInFooter(),
1039            omit_fields=self.omit_fields,)
1040
1041class PlagTestInfoPage(KofaPage):
1042    "Landing page after plagiation test payment"
1043    grok.context(ICustomStudentOnlinePayment)
1044    grok.name('plagtestinfo')
1045    grok.require('waeup.viewStudent')
1046
1047    def update(self):
1048        if self.context.p_state != 'paid' \
1049            or self.context.p_category != 'plag_test':
1050            self.flash(_('Forbidden'), type="danger")
1051            self.redirect(self.url(self.context))
1052        return super(PlagTestInfoPage, self).update()
1053
1054    @property
1055    def facdep(self):
1056        facdepkey = "%s-%s" % (self.context.student.faccode,
1057                               self.context.student.depcode)
1058        return DEPLINKS[facdepkey]
1059
1060class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
1061    """Deliver a PDF Admission slip.
1062    """
1063
1064    @property
1065    def post_text_pt(self):
1066        datelist = self.context.history.messages[0].split()[0].split('-')
1067        creation_date = u'%s/%s/%s' % (datelist[2], datelist[1], datelist[0])
1068        return (
1069            'Your Kofa student record was created on %s. <br/><br/>'
1070            'Please Note: This admission for '
1071            'Undergraduate Part-Time and Undergraduate Sandwich is incomplete '
1072            'until you have successfully applied on the <b>JAMB CAPS PORTAL</b>.  '
1073            'Ignore this if you have completed your own <b>pre-admission</b> '
1074            'activities on the JAMB website.' % creation_date)
1075
1076    def render(self):
1077        students_utils = getUtility(IStudentsUtils)
1078        letterhead_path = os.path.join(
1079            os.path.dirname(__file__), 'static', 'letterhead_admission.jpg')
1080        if not os.path.exists(letterhead_path):
1081            letterhead_path = None
1082        if self.context.current_mode in ('ug_pt', 'ug_sw'):
1083            return students_utils.renderPDFAdmissionLetter(self,
1084                self.context.student, omit_fields=self.omit_fields,
1085                letterhead_path=letterhead_path, post_text=self.post_text_pt)
1086        return students_utils.renderPDFAdmissionLetter(self,
1087            self.context.student, omit_fields=self.omit_fields,
1088            letterhead_path=letterhead_path, post_text=None)
Note: See TracBrowser for help on using the repository browser.