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

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

Allow different course gradings according to new course ticket attribute 'grading_sys'.

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