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

Last change on this file since 18016 was 18008, checked in by Henrik Bettermann, 5 days ago

Customize correctly.

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