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

Last change on this file since 17845 was 17845, checked in by Henrik Bettermann, 4 months ago

Show NYSC request info on fee payment history slip.

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