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

Last change on this file since 16439 was 16439, checked in by Henrik Bettermann, 4 years ago

Customize CustomStudyCourseManageFormPage?.

  • Property svn:keywords set to Id
File size: 34.5 KB
RevLine 
[8911]1## $Id: browser.py 16439 2021-03-30 09:40:15Z 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
[16382]19from datetime import datetime
[8911]20from zope.i18n import translate
[13719]21from zope.security import checkPermission
[9210]22from zope.schema.interfaces import ConstraintNotSatisfied
[12856]23from zope.formlib.textwidgets import BytesDisplayWidget
[9380]24from zope.component import getUtility
[16439]25from zope.event import notify
[9281]26from hurry.workflow.interfaces import IWorkflowInfo
[16439]27from waeup.kofa.utils.helpers import get_current_principal
[11069]28from waeup.kofa.interfaces import (
29    REQUESTED, IExtFileStore, IKofaUtils, IObjectHistory)
[8911]30from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
[12121]31from waeup.kofa.browser.layout import action, KofaEditFormPage, UtilityView
[9205]32from waeup.kofa.students.browser import (
[15352]33    StudentBaseEditFormPage,
[9686]34    StudyLevelEditFormPage, StudyLevelDisplayFormPage,
[13063]35    StudentBasePDFFormPage, ExportPDFCourseRegistrationSlip,
[10025]36    CourseTicketDisplayFormPage, StudentTriggerTransitionFormPage,
[11069]37    msave, emit_lock_message,
[13063]38    StudentActivateView, StudentDeactivateView,
[13719]39    ExportPDFTranscriptSlip,
[15574]40    PaymentsManageFormPage,
[16439]41    StartClearancePage,
42    StudyCourseManageFormPage)
[12845]43from waeup.kofa.students.workflow import (CREATED, ADMITTED, PAID,
44    CLEARANCE, REQUESTED, RETURNING, CLEARED, REGISTERED, VALIDATED,
[16171]45    GRADUATED, TRANSREQ, TRANSVAL, TRANSREL, FORBIDDEN_POSTGRAD_TRANS)
[9686]46from waeup.kofa.students.interfaces import IStudentsUtils, ICourseTicket
[9251]47from waeup.kofa.students.workflow import FORBIDDEN_POSTGRAD_TRANS
[8911]48from kofacustom.nigeria.students.browser import (
49    NigeriaOnlinePaymentDisplayFormPage,
[9251]50    NigeriaStudentBaseManageFormPage,
[9380]51    NigeriaStudentClearanceEditFormPage,
[8911]52    NigeriaOnlinePaymentAddFormPage,
[13063]53    NigeriaExportPDFPaymentSlip,
54    NigeriaExportPDFClearanceSlip,
[13297]55    NigeriaExportPDFBedTicketSlip,
[12856]56    NigeriaStudentPersonalDisplayFormPage,
[13085]57    NigeriaStudentPersonalManageFormPage,
[15267]58    NigeriaStudentPersonalEditFormPage,
[15371]59    NigeriaAccommodationManageFormPage,
[15975]60    NigeriaAccommodationDisplayFormPage,
[15371]61    NigeriaStudentBaseDisplayFormPage,
[16361]62    NigeriaStudentFilesUploadPage,
[9281]63    )
[8911]64
[9210]65from waeup.uniben.students.interfaces import (
[12121]66    ICustomStudent,
[15352]67    ICustomStudentBase,
[12856]68    ICustomStudentOnlinePayment,
69    ICustomStudentStudyCourse,
[11552]70    ICustomStudentStudyLevel,
71    ICustomUGStudentClearance,
[12856]72    ICustomPGStudentClearance,
[13085]73    ICustomStudentPersonal,
[16382]74    ICustomStudentPersonalEdit,
75    IMedicalHistory)
[9210]76from waeup.uniben.interfaces import MessageFactory as _
[8911]77
[15371]78class CustomStudentBaseDisplayFormPage(NigeriaStudentBaseDisplayFormPage):
79    """ Page to display student base data
80    """
81    form_fields = grok.AutoFields(ICustomStudentBase).omit(
82        'password', 'suspended', 'suspended_comment',
[16088]83        'flash_notice', 'provisionally_cleared', 'parents_email')
[15371]84    form_fields[
85        'financial_clearance_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
86
[16088]87class CustomStudentBaseManageFormPage(NigeriaStudentBaseManageFormPage):
88    """ View to manage student base data
89    """
90    form_fields = grok.AutoFields(ICustomStudentBase).omit(
91        'student_id', 'adm_code', 'suspended',
92        'financially_cleared_by', 'financial_clearance_date',
93        'parents_email')
[15371]94
[8911]95class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage):
96    """ Page to view an online payment ticket
97    """
98    grok.context(ICustomStudentOnlinePayment)
[9775]99    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
[9993]100        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
[8911]101    form_fields[
102        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
103    form_fields[
104        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
105
[15574]106class CustomStartClearancePage(StartClearancePage):
107
108    @property
109    def with_ac(self):
110        if self.context.faccode == 'DCOEM':
111            return False
112        return True
113
[16363]114
115CLEARANCE_FLASH_MESSAGE = """
116If you have not presented for physical clearance, scan your WAEC, NECO
[16364]117and other O level results scratch cards on one document and
118attach to the form below (Scans > O Level Results Scratch Card).
[16363]119Then come back to check for your successful cleared status as from 3 days
120after successful clearance request.
121If status is cleared, pay your school charges and proceed to the
122Dean's Office to collect the signed eligibility form.
123"""
124
[9380]125class CustomStudentClearanceEditFormPage(NigeriaStudentClearanceEditFormPage):
126    """ View to edit student clearance data by student
127    """
128
[11552]129    @property
130    def form_fields(self):
131        if self.context.is_postgrad:
132            form_fields = grok.AutoFields(ICustomPGStudentClearance).omit(
[12391]133            'clearance_locked', 'nysc_location', 'clr_code', 'officer_comment',
134            'physical_clearance_date')
[11552]135        else:
136            form_fields = grok.AutoFields(ICustomUGStudentClearance).omit(
[12391]137            'clearance_locked', 'clr_code', 'officer_comment',
138            'physical_clearance_date')
[11552]139            form_fields['date_of_birth'].for_display = True
140            form_fields['nationality'].for_display = True
141            form_fields['lga'].for_display = True
142        return form_fields
143
[15666]144    def dataNotComplete(self):
[9380]145        store = getUtility(IExtFileStore)
146        if not store.getFileByContext(self.context, attr=u'birth_certificate.jpg'):
147            return _('No birth certificate uploaded.')
148        if not store.getFileByContext(self.context, attr=u'ref_let.jpg'):
149            return _('No guarantor/referee letter uploaded.')
150        if not store.getFileByContext(self.context, attr=u'acc_let.jpg'):
151            return _('No acceptance letter uploaded.')
152        if not store.getFileByContext(self.context, attr=u'fst_sit_scan.jpg'):
153            return _('No first sitting result uploaded.')
[9395]154        #if not store.getFileByContext(self.context, attr=u'scd_sit_scan.jpg'):
155        #    return _('No second sitting result uploaded.')
[9380]156        if not store.getFileByContext(self.context, attr=u'secr_cults.jpg'):
[9848]157            return _('No affidavit of non-membership of secret cults uploaded.')
[9380]158        return False
159
[16363]160    def update(self):
161        self.flash(CLEARANCE_FLASH_MESSAGE, type="warning")
162        return super(CustomStudentClearanceEditFormPage, self).update()
163
[8911]164class CustomOnlinePaymentAddFormPage(NigeriaOnlinePaymentAddFormPage):
165    """ Page to add an online payment ticket
166    """
167    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).select(
[15666]168        'p_combi')
[8911]169
[13063]170class CustomExportPDFPaymentSlip(NigeriaExportPDFPaymentSlip):
[8911]171    """Deliver a PDF slip of the context.
172    """
173    grok.context(ICustomStudentOnlinePayment)
[9775]174    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
[15688]175        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item', 'p_combi')
[8911]176    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
[9205]177    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
178
179
[13063]180class CustomExportPDFClearanceSlip(NigeriaExportPDFClearanceSlip):
[9551]181    """Deliver a PDF slip of the context.
182    """
183
[13303]184    @property
185    def omit_fields(self):
186        omit_fields = ('password', 'suspended', 'suspended_comment',
[13717]187                       'phone', 'adm_code', 'email', 'date_of_birth',
188                       'flash_notice')
[14902]189        if self.context.is_jupeb:
[13303]190            omit_fields += ('faculty', 'department')
191        return omit_fields
[11537]192
[13299]193    @property
194    def label(self):
195        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13300]196        line0 = ''
[14902]197        if self.context.is_jupeb:
[13335]198            line0 = 'Joint Universities Preliminary Examinations Board (JUPEB)\n'
[13300]199        line1 = translate(_('Clearance Slip of'),
[13299]200            'waeup.kofa', target_language=portal_language) \
201            + ' %s' % self.context.display_fullname
[13335]202        return '%s%s' % (line0, line1)
[13299]203
[12846]204    def _sigsInFooter(self):
[12845]205        isStudent = getattr(
206            self.request.principal, 'user_type', None) == 'student'
[12852]207        if not isStudent and self.context.state in (CLEARED, RETURNING):
[12846]208            return (_('Date, Student Signature'),
209                    _('Date, Clearance Officer Signature'),
210                    )
211        return ()
[12845]212
[9551]213    def render(self):
214        studentview = StudentBasePDFFormPage(self.context.student,
215            self.request, self.omit_fields)
216        students_utils = getUtility(IStudentsUtils)
217        return students_utils.renderPDF(
218            self, 'clearance_slip.pdf',
219            self.context.student, studentview, signatures=self._signatures(),
[10271]220            sigs_in_footer=self._sigsInFooter(), show_scans=False,
221            omit_fields=self.omit_fields)
[9551]222
[12121]223
[13063]224class ExportClearanceInvitationSlip(UtilityView, grok.View):
[12121]225    """Deliver an invitation letter to physical clearance.
226
227    This form page is available only in Uniben.
228    """
229    grok.context(ICustomStudent)
230    grok.name('clearance_invitation_slip.pdf')
231    grok.require('waeup.viewStudent')
232    prefix = 'form'
233
[12263]234    label = u'Invitation Letter for Physical Clearance'
[12121]235
236    omit_fields = (
237        'suspended', 'phone', 'email',
238        'adm_code', 'suspended_comment',
239        'date_of_birth', 'current_level',
[12150]240        'department', 'current_mode',
[13717]241        'entry_session', 'matric_number', 'sex',
242        'flash_notice')
[12121]243
244    form_fields = []
245
246    @property
247    def note(self):
248        if self.context.physical_clearance_date:
249            return """
[12147]250<br /><br /><br /><br /><font size='12'>
251Dear %s,
252<br /><br /><br />
[12264]253You are invited for your physical clearance on:
[12121]254<br /><br />
[12264]255<strong>%s</strong>.
256<br /><br />
[12265]257Please bring along this letter of invitation to the University Main Auditorium
[12147]258<br /><br />
[12263]259on your clearance date.
[12147]260<br /><br /><br />
[12263]261Signed,
[12147]262<br /><br />
263The Registrar<br />
[12121]264</font>
265
[12147]266""" % (self.context.display_fullname, self.context.physical_clearance_date)
[12121]267        return
268
[12122]269
270    def update(self):
271        if self.context.student.state != REQUESTED \
272            or not  self.context.student.physical_clearance_date:
273            self.flash(_('Forbidden'), type="warning")
274            self.redirect(self.url(self.context))
275
[12121]276    def render(self):
277        studentview = StudentBasePDFFormPage(self.context.student,
278            self.request, self.omit_fields)
279        students_utils = getUtility(IStudentsUtils)
280        return students_utils.renderPDF(
281            self, 'clearance_invitation_slip',
282            self.context.student, studentview,
283            omit_fields=self.omit_fields,
284            note=self.note)
285
[13723]286class ExportExaminationScheduleSlip(UtilityView, grok.View):
287    """Deliver a examination schedule slip.
288
[14689]289    This form page is available only in Uniben and AAUE.
[13723]290    """
291    grok.context(ICustomStudent)
292    grok.name('examination_schedule_slip.pdf')
293    grok.require('waeup.viewStudent')
294    prefix = 'form'
295
296    label = u'Examination Schedule Slip'
297
298    omit_fields = (
299        'suspended', 'phone', 'email',
300        'adm_code', 'suspended_comment',
301        'date_of_birth', 'current_level',
302        'current_mode',
303        'entry_session',
304        'flash_notice')
305
306    form_fields = []
307
308    @property
309    def note(self):
310        return """
311<br /><br /><br /><br /><font size='12'>
312Your examination date, time and venue is scheduled as follows:
313<br /><br />
314<strong>%s</strong>
315</font>
316
317""" % self.context.flash_notice
318        return
319
320
321    def update(self):
322        if not self.context.flash_notice \
323            or not 'exam' in self.context.flash_notice.lower():
324            self.flash(_('Forbidden'), type="warning")
325            self.redirect(self.url(self.context))
326
327    def render(self):
328        studentview = StudentBasePDFFormPage(self.context.student,
329            self.request, self.omit_fields)
330        students_utils = getUtility(IStudentsUtils)
331        return students_utils.renderPDF(
332            self, 'examination_schedule_slip',
333            self.context.student, studentview,
334            omit_fields=self.omit_fields,
335            note=self.note)
336
[15371]337class SwitchLibraryAccessView(UtilityView, grok.View):
338    """ Switch the library attribute
339    """
340    grok.context(ICustomStudent)
341    grok.name('switch_library_access')
342    grok.require('waeup.switchLibraryAccess')
343
344    def update(self):
345        if self.context.library:
346            self.context.library = False
347            self.context.writeLogMessage(self, 'library access disabled')
348            self.flash(_('Library access disabled'))
349        else:
350            self.context.library = True
351            self.context.writeLogMessage(self, 'library access enabled')
352            self.flash(_('Library access enabled'))
353        self.redirect(self.url(self.context))
354        return
355
356    def render(self):
357        return
358
[15352]359class ExportJHLIdCard(UtilityView, grok.View):
[15371]360    """Deliver an id card for the John Harris Library.
[15352]361    """
362    grok.context(ICustomStudent)
363    grok.name('jhl_idcard.pdf')
364    grok.require('waeup.viewStudent')
365    prefix = 'form'
366
[15403]367    label = u"John Harris Library Clearance"
[15352]368
369    omit_fields = (
[15371]370        'suspended', 'email', 'phone',
[15352]371        'adm_code', 'suspended_comment',
[15371]372        'date_of_birth',
[15352]373        'current_mode', 'certificate',
374        'entry_session',
375        'flash_notice')
376
377    form_fields = []
378
379    def _sigsInFooter(self):
[15371]380        isStudent = getattr(
381            self.request.principal, 'user_type', None) == 'student'
382        if isStudent:
383            return ''
[15352]384        return (_("Date, Reader's Signature"),
385                _("Date, Circulation Librarian's Signature"),
386                )
387
[15371]388    def update(self):
389        if not self.context.library:
390            self.flash(_('Forbidden!'), type="danger")
391            self.redirect(self.url(self.context))
392        return
393
[15352]394    @property
395    def note(self):
396        return """
397<br /><br /><br /><br /><font size='12'>
398This is to certify that the bearer whose photograph and other details appear
399 overleaf is a registered user of <b>John Harris Library, University of Benin</b>.
400 The card is not transferable. A replacement fee is charged for a loss,
401 mutilation or otherwise. If found, please, return to John Harris Library,
402 University of Benin, Benin City.
403</font>
404
405"""
406        return
407
408    def render(self):
409        studentview = StudentBasePDFFormPage(self.context.student,
410            self.request, self.omit_fields)
411        students_utils = getUtility(IStudentsUtils)
412        return students_utils.renderPDF(
413            self, 'jhl_idcard',
414            self.context.student, studentview,
415            omit_fields=self.omit_fields,
416            sigs_in_footer=self._sigsInFooter(),
417            note=self.note)
418
[14834]419class ExportJUPEBResultSlip(ExportExaminationScheduleSlip):
420    """Deliver a JUPEB result slip.
421
422    This form page is available only in Uniben.
423    """
424
425    grok.name('jupeb_result_slip.pdf')
426    label = u'JUPEB Result Slip'
427
428    @property
429    def note(self):
430        return """
431<br /><br /><br /><br /><font size='12'>
432<strong>%s</strong>
433</font>
434<br /><br /><br /><br />
435<font size='8'>
436Key: A = 5, B = 4, C = 3, D = 2, E = 1, F = 0, X = Absent, Q = Cancelled
437</font>
438
439""" % self.context.flash_notice
440        return
441
442    def update(self):
[14902]443        if not self.context.flash_notice or not self.context.is_jupeb \
[14835]444            or not 'results' in self.context.flash_notice.lower():
[14834]445            self.flash(_('Forbidden'), type="warning")
446            self.redirect(self.url(self.context))
447
[12856]448class CustomStudentPersonalDisplayFormPage(
449    NigeriaStudentPersonalDisplayFormPage):
450    """ Page to display student personal data
451    """
452
453    form_fields = grok.AutoFields(ICustomStudentPersonal)
454    form_fields['perm_address'].custom_widget = BytesDisplayWidget
455    form_fields['next_kin_address'].custom_widget = BytesDisplayWidget
456    form_fields[
457        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
458
459class CustomStudentPersonalManageFormPage(
460    NigeriaStudentPersonalManageFormPage):
461    """ Page to manage personal data
462    """
463
464    form_fields = grok.AutoFields(ICustomStudentPersonal)
465    form_fields['personal_updated'].for_display = True
466    form_fields[
467        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
468
[13085]469class CstomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage):
470    """ Page to edit personal data
471    """
472    form_fields = grok.AutoFields(
473        ICustomStudentPersonalEdit).omit('personal_updated')
474
[9210]475class StudyCourseCOEditFormPage(KofaEditFormPage):
[9281]476    """ Page to edit the student study course data by clearance officers.
[9210]477
478    This form page is available only in Uniben.
479    """
480    grok.context(ICustomStudentStudyCourse)
481    grok.name('edit_level')
482    grok.require('waeup.clearStudent')
483    label = _('Edit current level')
484    pnav = 4
485    form_fields = grok.AutoFields(
486        ICustomStudentStudyCourse).select('current_level')
487
488    def update(self):
489        if not (self.context.is_current and
490            self.context.student.state == REQUESTED):
491            emit_lock_message(self)
492            return
493        super(StudyCourseCOEditFormPage, self).update()
494        return
495
496    @action(_('Save'), style='primary')
497    def save(self, **data):
498        try:
499            msave(self, **data)
500        except ConstraintNotSatisfied:
501            # The selected level might not exist in certificate
502            self.flash(_('Current level not available for certificate.'))
503            return
[9281]504        return
505
506class CustomStudyLevelEditFormPage(StudyLevelEditFormPage):
507    """ Page to edit the student study level data by students.
508
509    """
[9686]510    grok.template('studyleveleditpage')
[9281]511
[9686]512class CustomStudyLevelDisplayFormPage(StudyLevelDisplayFormPage):
513    """ Page to display student study levels
514    """
515    grok.template('studylevelpage')
516
[16427]517    @property
518    def view_scores_allowed(self):
519        return checkPermission('waeup.manageStudent', self.context)
520
[16439]521class CustomStudyCourseManageFormPage(StudyCourseManageFormPage):
522    """ Page to edit the student study course data
523    """
524
525    @action(_('Save'), style='primary')
526    def save(self, **data):
527        user = get_current_principal()
528        if user.id not in ('admin', 'med', 'zope.mgr', 'zope.manager',
529                           'benamechi', 'tbazuaye'):
530            if data['previous_verdict'] == 'R' and self.context.previous_verdict != 'R':
531                self.flash(_('You are not entitled to assign this verdict.'),
532                           type="warning")
533                return
534            if data['current_verdict'] == 'R' and self.context.current_verdict != 'R':
535                self.flash(_('You are not entitled to assign this verdict.'),
536                           type="warning")
537                return
538        try:
539            msave(self, **data)
540        except ConstraintNotSatisfied:
541            # The selected level might not exist in certificate
542            self.flash(_('Current level not available for certificate.'),
543                       type="warning")
544            return
545        #notify(grok.ObjectModifiedEvent(self.context.__parent__))
546        return
547
[13063]548class CustomExportPDFCourseRegistrationSlip(
549    ExportPDFCourseRegistrationSlip):
[9686]550    """Deliver a PDF slip of the context.
551    """
552
[9921]553    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
[15404]554        'level_verdict', 'gpa', 'level', 'transcript_remark')
[9921]555
[12855]556    def update(self):
557        if self.context.student.state != REGISTERED \
558            or self.context.student.current_level != self.context.level:
559            self.flash(_('Forbidden'), type="warning")
560            self.redirect(self.url(self.context))
561
[10441]562    @property
563    def tabletitle(self):
564        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
565        tabletitle = []
566        tabletitle.append(translate(_('1st Semester Courses'), 'waeup.kofa',
567            target_language=portal_language))
568        tabletitle.append(translate(_('2nd Semester Courses'), 'waeup.kofa',
569            target_language=portal_language))
570        tabletitle.append(translate(_('Level Courses'), 'waeup.kofa',
571            target_language=portal_language))
572        tabletitle.append(translate(_('1st Trimester Courses'), 'waeup.kofa',
573            target_language=portal_language))
574        tabletitle.append(translate(_('2nd Trimester Courses'), 'waeup.kofa',
575            target_language=portal_language))
576        tabletitle.append(translate(_('3rd Trimester Courses'), 'waeup.kofa',
577            target_language=portal_language))
578        return tabletitle
579
[9686]580    def render(self):
581        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[9909]582        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
583        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
584        Dept = translate('Dept.', 'waeup.kofa', target_language=portal_language)
585        Faculty = translate('Faculty', 'waeup.kofa', target_language=portal_language)
586        Cred = translate(_('Credits'), 'waeup.uniben', target_language=portal_language)
[9686]587        studentview = StudentBasePDFFormPage(self.context.student,
588            self.request, self.omit_fields)
589        students_utils = getUtility(IStudentsUtils)
[10441]590
591        tabledata = []
592        tableheader = []
593        for i in range(1,7):
594            tabledata.append(sorted(
595                [value for value in self.context.values() if value.semester == i],
596                key=lambda value: str(value.semester) + value.code))
597            tableheader.append([(Code,'code', 2.5),
598                             (Title,'title', 5),
599                             (Dept,'dcode', 1.5), (Faculty,'fcode', 1.5),
600                             (Cred, 'credits', 1.5),
601                             ])
[9686]602        return students_utils.renderPDF(
603            self, 'course_registration_slip.pdf',
604            self.context.student, studentview,
[10441]605            tableheader=tableheader,
606            tabledata=tabledata,
[10271]607            omit_fields=self.omit_fields
[9908]608            )
[9848]609
[15401]610class ExportPDFCourseResultSlip(ExportPDFCourseRegistrationSlip):
[9848]611    """Deliver a PDF slip of the context.
612    """
613
614    grok.name('course_result_slip.pdf')
615
[15401]616    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit('level')
617
[9848]618    @property
[10441]619    def tabletitle(self):
620        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
621        tabletitle = []
622        tabletitle.append(translate(_('1st Semester Courses'), 'waeup.kofa',
623            target_language=portal_language))
624        tabletitle.append(translate(_('2nd Semester Courses'), 'waeup.kofa',
625            target_language=portal_language))
626        tabletitle.append(translate(_('Level Courses'), 'waeup.kofa',
627            target_language=portal_language))
628        tabletitle.append(translate(_('1st Trimester Courses'), 'waeup.kofa',
629            target_language=portal_language))
630        tabletitle.append(translate(_('2nd Trimester Courses'), 'waeup.kofa',
631            target_language=portal_language))
632        tabletitle.append(translate(_('3rd Trimester Courses'), 'waeup.kofa',
633            target_language=portal_language))
634        return tabletitle
635
636    @property
[9848]637    def label(self):
638        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
639        lang = self.request.cookies.get('kofa.language', portal_language)
640        level_title = translate(self.context.level_title, 'waeup.kofa',
641            target_language=lang)
642        return translate(_('Course Result Slip'),
643            'waeup.uniben', target_language=portal_language) \
644            + ' %s' % level_title
645
646    def render(self):
647        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[9909]648        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
649        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
650        Dept = translate('Dept.', 'waeup.kofa', target_language=portal_language)
651        Faculty = translate('Faculty', 'waeup.kofa', target_language=portal_language)
652        Cred = translate(_('Credits'), 'waeup.uniben', target_language=portal_language)
653        Grade = translate('Grade', 'waeup.kofa', target_language=portal_language)
[9848]654        studentview = StudentBasePDFFormPage(self.context.student,
655            self.request, self.omit_fields)
656        students_utils = getUtility(IStudentsUtils)
[10441]657
658        tabledata = []
659        tableheader = []
660        for i in range(1,7):
661            tabledata.append(sorted(
662                [value for value in self.context.values() if value.semester == i],
663                key=lambda value: str(value.semester) + value.code))
664            tableheader.append([(Code,'code', 2.5),
665                             (Title,'title', 5),
666                             (Dept,'dcode', 1.5), (Faculty,'fcode', 1.5),
667                             (Cred, 'credits', 1.5),
668                             (Grade, 'grade', 1.5),
669                             ])
[9908]670        return students_utils.renderPDF(
[15401]671            self, 'course_result_slip.pdf',
[9908]672            self.context.student, studentview,
[10441]673            tableheader=tableheader,
674            tabledata=tabledata,
[10271]675            omit_fields=self.omit_fields
[9908]676            )
[9686]677
678class CustomCourseTicketDisplayFormPage(CourseTicketDisplayFormPage):
679    """ Page to display course tickets
680    """
681    form_fields = grok.AutoFields(ICourseTicket).omit('score')
[11069]682
[13063]683class CustomStudentActivateView(StudentActivateView):
[11069]684    """ Activate student account
685    """
686
687    def update(self):
688        self.context.suspended = False
689        self.context.writeLogMessage(self, 'account activated')
690        history = IObjectHistory(self.context)
691        history.addMessage('Student account activated', user='undisclosed')
692        self.flash(_('Student account has been activated.'))
693        self.redirect(self.url(self.context))
694        return
695
[13063]696class CustomStudentDeactivateView(StudentDeactivateView):
[11069]697    """ Deactivate student account
698    """
699    def update(self):
700        self.context.suspended = True
701        self.context.writeLogMessage(self, 'account deactivated')
702        history = IObjectHistory(self.context)
703        history.addMessage('Student account deactivated', user='undisclosed')
704        self.flash(_('Student account has been deactivated.'))
705        self.redirect(self.url(self.context))
706        return
[12845]707
[13063]708class CustomExportPDFTranscriptSlip(ExportPDFTranscriptSlip):
[12845]709    """Deliver a PDF slip of the context.
710    """
711
[16171]712    def _sigsInFooter(self):
713        isStudent = getattr(
714            self.request.principal, 'user_type', None) == 'student'
715        if not isStudent and self.context.student.state in (TRANSVAL, TRANSREL):
716            return (_('D. R. (Exams & Records)'),_('Current Dean of Faculty'),)
717        return ()
[12845]718
[14689]719    #def _signatures(self):
720    #    return ([(
721    #        'Current HD<br /> D. R. (Exams & Records)<br /> '
722    #        'For: Registrar')],)
[12845]723
724    def render(self):
725        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
726        Term = translate(_('Term'), 'waeup.kofa', target_language=portal_language)
727        Code = translate(_('Code'), 'waeup.kofa', target_language=portal_language)
728        Title = translate(_('Title'), 'waeup.kofa', target_language=portal_language)
729        Cred = translate(_('Credits'), 'waeup.kofa', target_language=portal_language)
730        #Score = translate(_('Score'), 'waeup.kofa', target_language=portal_language)
731        Grade = translate(_('Grade'), 'waeup.kofa', target_language=portal_language)
732        studentview = StudentBasePDFFormPage(self.context.student,
733            self.request, self.omit_fields)
734        students_utils = getUtility(IStudentsUtils)
735
736        tableheader = [(Code,'code', 2.5),
737                         (Title,'title', 8.5),
738                         (Term, 'semester', 1.5),
739                         (Cred, 'credits', 1.5),
740                         #(Score, 'score', 1.5),
741                         (Grade, 'grade', 1.5),
742                         ]
743
[15164]744        pdfstream = students_utils.renderPDFTranscript(
[12845]745            self, 'transcript.pdf',
746            self.context.student, studentview,
747            omit_fields=self.omit_fields,
748            tableheader=tableheader,
749            signatures=self._signatures(),
750            sigs_in_footer=self._sigsInFooter(),
[15164]751            digital_sigs=self._digital_sigs(),
752            save_file=self._save_file(),
[13297]753            )
[15164]754        if not pdfstream:
755            self.redirect(self.url(self.context.student))
756            return
757        return pdfstream
[13297]758
759class CustomExportPDFBedTicketSlip(NigeriaExportPDFBedTicketSlip):
760    """Deliver a PDF slip of the context.
761    """
[13317]762    omit_fields = ('password', 'suspended', 'suspended_comment',
[13717]763        'phone', 'adm_code', 'email', 'date_of_birth', 'flash_notice')
[13297]764
[13719]765class CustomPaymentsManageFormPage(PaymentsManageFormPage):
766    """ Page to manage the student payments. This manage form page is for
767    both students and students officers. Uniben does not allow students
768    to remove any payment ticket.
769    """
770    @property
771    def manage_payments_allowed(self):
[13723]772        return checkPermission('waeup.manageStudent', self.context)
[15267]773
[15975]774class CustomAccommodationDisplayFormPage(NigeriaAccommodationDisplayFormPage):
775    """ Page to view bed tickets.
776    """
777    with_hostel_selection = True
778
[15267]779class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
780    """ Page to manage bed tickets.
781    This manage form page is for both students and students officers.
782    """
[15352]783    with_hostel_selection = True
784
785class CustomStudentBaseEditFormPage(StudentBaseEditFormPage):
786    """ View to edit student base data
787    """
788    form_fields = grok.AutoFields(ICustomStudentBase).select(
789        'email', 'phone')
790    form_fields['email'].field.required = True
[16361]791
792class CustomStudentFilesUploadPage(NigeriaStudentFilesUploadPage):
793    """ View to upload passport picture.
794
795    Students are not allowed to change the picture if they
796    passed the regular Kofa application.
797    """
798
799    def update(self):
[16362]800        # Uniben: Only 2020 session students are allowed to edit the picture.
801        if self.context.entry_session != 2020:
802            emit_lock_message(self)
803            return
[16361]804        # Passport pictures must not be editable if application slip
805        # exists.
806        slip = getUtility(IExtFileStore).getFileByContext(
807            self.context, 'application_slip')
808        PORTRAIT_CHANGE_STATES = getUtility(IStudentsUtils).PORTRAIT_CHANGE_STATES
809        if self.context.state not in PORTRAIT_CHANGE_STATES or slip is not None:
810            emit_lock_message(self)
811            return
812        super(StudentFilesUploadPage, self).update()
[16382]813        return
814
[16385]815
816
817
818from zope.schema.vocabulary import SimpleVocabulary
819from zope.formlib.itemswidgets import RadioWidget
820from zope.formlib.itemswidgets import SelectWidget, DropdownWidget
821
822def CustomBooleanRadioWidget(field, request, true=_('yes'), false=_('no')):
823    vocabulary = SimpleVocabulary.fromItems( ((true, True), (false, False)) )
824    widget = RadioWidget(field, vocabulary, request)
825    widget.required = False
826    return widget
827
[16382]828class StudentMedicalHistoryEditFormPage(KofaEditFormPage):
[16383]829    """ Page to edit medical data
[16382]830    """
831    grok.context(ICustomStudent)
832    grok.name('edit_medical')
833    grok.require('waeup.handleStudent')
[16385]834    label = _('Medical Questionnaire')
[16382]835    pnav = 4
836
[16386]837    def _medicalQuestPaymentMade(self, student, session):
838        if len(student['payments']):
839            for ticket in student['payments'].values():
840                if ticket.p_state == 'paid' and \
841                    ticket.p_category == 'medical_quest' and \
842                    ticket.p_session == session:
843                    return True
844        return False
845
846    def update(self):
847        if not self._medicalQuestPaymentMade(
848            self.context, self.context.current_session):
849            self.flash('Please pay medical questionnaire payment first.',
850                type="warning")
851            self.redirect(self.url(self.context))
852            return
853        return super(StudentMedicalHistoryEditFormPage, self).update()
854
[16382]855    @property
[16385]856    def form_fields(self):
857        form_fields = grok.AutoFields(IMedicalHistory)
858        form_fields['medical_updated'].for_display = True
859        for field in ('fever', 'headaches', 'catarrh', 'cough', 'sore_throat',
860                      'breathing', 'sneezing', 'weakness', 'body_pains',
861                      'smell', 'taste', 'asthma', 'hypertension', 'diabetes',
862                      'obesity', 'lagos_abuja', 'outside', 'company_suspected',
863                      'company_confirmed', 'positive', 'negative',
864                      'vaccination'):
865            form_fields[field].custom_widget = CustomBooleanRadioWidget
866        return form_fields
867
868    @property
[16382]869    def separators(self):
870        return getUtility(IStudentsUtils).SEPARATORS_DICT
871
872    @action(_('Save/Confirm'), style='primary')
873    def save(self, **data):
874        msave(self, **data)
875        self.context.medical_updated = datetime.utcnow()
876        return
877
[16383]878class StudentMedicalHistoryManageFormPage(StudentMedicalHistoryEditFormPage):
879    """ Page to manage medical data
880    """
881    grok.name('manage_medical')
882    grok.require('waeup.manageStudent')
[16385]883    label = _('Manage medical questionnaire data')
[16383]884
[16405]885    def update(self):
886        return super(StudentMedicalHistoryEditFormPage, self).update()
887
[16382]888class ExportPDFMedicalHistorySlip(grok.View):
889    """Deliver a PDF slip of the context.
890    """
891    grok.context(ICustomStudent)
[16385]892    grok.name('medical_questionnaire_slip.pdf')
[16382]893    grok.require('waeup.viewStudent')
894    prefix = 'form'
895    form_fields = grok.AutoFields(IMedicalHistory)
896
897    omit_fields = ('password', 'suspended', 'suspended_comment',
898                   'adm_code', 'date_of_birth',
899                   'flash_notice', 'current_mode', 'entry_mode',
900                   'entry_session', 'parents_email', 'study_course',
901                   'current_level', 'reg_number', 'sex',
902                   'certificate')
903
904    @property
905    def title(self):
906        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[16385]907        return translate(_('Medical Questionnaire'), 'waeup.kofa',
[16382]908            target_language=portal_language)
909
910    @property
911    def label(self):
912        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[16385]913        return translate(_('Medical Questionnaire Slip of'),
[16382]914            'waeup.kofa', target_language=portal_language) \
915            + ' %s' % self.context.display_fullname
916
917    def render(self):
918        studentview = StudentBasePDFFormPage(self.context.student,
919            self.request, self.omit_fields)
920        students_utils = getUtility(IStudentsUtils)
921        return students_utils.renderPDF(
[16385]922            self, 'medical_questionnaire_slip.pdf',
[16382]923            self.context.student, studentview,
924            omit_fields=self.omit_fields,)
Note: See TracBrowser for help on using the repository browser.