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

Last change on this file since 17049 was 17049, checked in by Henrik Bettermann, 2 years ago

Disable student transcript view again.

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