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

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

Allow postgrad students to change their passport picture.

  • Property svn:keywords set to Id
File size: 34.8 KB
Line 
1## $Id: browser.py 17142 2022-10-26 12:03:56Z 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
801    def update(self):
802        # Postgrad students should allowed to change their picture whenever they want.
803        if self.context.is_postgrad:
804            return
805        if self.context.is_jupeb:
806            emit_lock_message(self)
807            return           
808        super(StudentFilesUploadPage, self).update()
809        return
810
811
812
813from zope.schema.vocabulary import SimpleVocabulary
814from zope.formlib.itemswidgets import RadioWidget
815from zope.formlib.itemswidgets import SelectWidget, DropdownWidget
816
817def CustomBooleanRadioWidget(field, request, true=_('yes'), false=_('no')):
818    vocabulary = SimpleVocabulary.fromItems( ((true, True), (false, False)) )
819    widget = RadioWidget(field, vocabulary, request)
820    widget.required = False
821    return widget
822
823class StudentMedicalHistoryEditFormPage(KofaEditFormPage):
824    """ Page to edit medical data
825    """
826    grok.context(ICustomStudent)
827    grok.name('edit_medical')
828    grok.require('waeup.handleStudent')
829    label = _('Medical Questionnaire')
830    pnav = 4
831
832    def _medicalQuestPaymentMade(self, student, session):
833        if len(student['payments']):
834            for ticket in student['payments'].values():
835                if ticket.p_state == 'paid' and \
836                    ticket.p_category == 'medical_quest' and \
837                    ticket.p_session == session:
838                    return True
839        return False
840
841    def update(self):
842        if not self._medicalQuestPaymentMade(
843            self.context, self.context.current_session):
844            self.flash('Please pay medical questionnaire payment first.',
845                type="warning")
846            self.redirect(self.url(self.context))
847            return
848        return super(StudentMedicalHistoryEditFormPage, self).update()
849
850    @property
851    def form_fields(self):
852        form_fields = grok.AutoFields(IMedicalHistory)
853        form_fields['medical_updated'].for_display = True
854        for field in ('fever', 'headaches', 'catarrh', 'cough', 'sore_throat',
855                      'breathing', 'sneezing', 'weakness', 'body_pains',
856                      'smell', 'taste', 'asthma', 'hypertension', 'diabetes',
857                      'obesity', 'lagos_abuja', 'outside', 'company_suspected',
858                      'company_confirmed', 'positive', 'negative',
859                      'vaccination'):
860            form_fields[field].custom_widget = CustomBooleanRadioWidget
861        return form_fields
862
863    @property
864    def separators(self):
865        return getUtility(IStudentsUtils).SEPARATORS_DICT
866
867    @action(_('Save/Confirm'), style='primary')
868    def save(self, **data):
869        msave(self, **data)
870        self.context.medical_updated = datetime.utcnow()
871        return
872
873class StudentMedicalHistoryManageFormPage(StudentMedicalHistoryEditFormPage):
874    """ Page to manage medical data
875    """
876    grok.name('manage_medical')
877    grok.require('waeup.manageStudent')
878    label = _('Manage medical questionnaire data')
879
880    def update(self):
881        return super(StudentMedicalHistoryEditFormPage, self).update()
882
883class ExportPDFMedicalHistorySlip(grok.View):
884    """Deliver a PDF slip of the context.
885    """
886    grok.context(ICustomStudent)
887    grok.name('medical_questionnaire_slip.pdf')
888    grok.require('waeup.viewStudent')
889    prefix = 'form'
890    form_fields = grok.AutoFields(IMedicalHistory)
891
892    omit_fields = ('password', 'suspended', 'suspended_comment',
893                   'adm_code', 'date_of_birth',
894                   'flash_notice', 'current_mode', 'entry_mode',
895                   'entry_session', 'parents_email', 'study_course',
896                   'current_level', 'reg_number', 'sex',
897                   'certificate')
898
899    @property
900    def title(self):
901        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
902        return translate(_('Medical Questionnaire'), 'waeup.kofa',
903            target_language=portal_language)
904
905    @property
906    def label(self):
907        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
908        return translate(_('Medical Questionnaire Slip of'),
909            'waeup.kofa', target_language=portal_language) \
910            + ' %s' % self.context.display_fullname
911
912    def render(self):
913        studentview = StudentBasePDFFormPage(self.context.student,
914            self.request, self.omit_fields)
915        students_utils = getUtility(IStudentsUtils)
916        return students_utils.renderPDF(
917            self, 'medical_questionnaire_slip.pdf',
918            self.context.student, studentview,
919            omit_fields=self.omit_fields,)
920
921class PlagTestInfoPage(KofaPage):
922    "Landing page after plagiation test payment"
923    grok.context(ICustomStudentOnlinePayment)
924    grok.name('plagtestinfo')
925    grok.require('waeup.viewStudent')
926
927    def update(self):
928        if self.context.p_state != 'paid' \
929            or self.context.p_category != 'plag_test':
930            self.flash(_('Forbidden'), type="danger")
931            self.redirect(self.url(self.context))
932        return super(PlagTestInfoPage, self).update()
933
934    @property
935    def facdep(self):
936        facdepkey = "%s-%s" % (self.context.student.faccode,
937                               self.context.student.depcode)
938        return DEPLINKS[facdepkey]
Note: See TracBrowser for help on using the repository browser.