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

Last change on this file since 17814 was 17812, checked in by Henrik Bettermann, 7 months ago

Remove unused imports.

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