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

Last change on this file since 14801 was 14689, checked in by Henrik Bettermann, 8 years ago

Change signatures on transcripts.

  • Property svn:keywords set to Id
File size: 22.9 KB
Line 
1## $Id: browser.py 14689 2017-06-09 05:18:25Z henrik $
2##
3## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import grok
19from zope.i18n import translate
20from zope.security import checkPermission
21from zope.schema.interfaces import ConstraintNotSatisfied
22from zope.formlib.textwidgets import BytesDisplayWidget
23from zope.component import getUtility
24from hurry.workflow.interfaces import IWorkflowInfo
25from waeup.kofa.interfaces import (
26    REQUESTED, IExtFileStore, IKofaUtils, IObjectHistory)
27from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
28from waeup.kofa.browser.layout import action, KofaEditFormPage, UtilityView
29from waeup.kofa.students.browser import (
30    StudyLevelEditFormPage, StudyLevelDisplayFormPage,
31    StudentBasePDFFormPage, ExportPDFCourseRegistrationSlip,
32    CourseTicketDisplayFormPage, StudentTriggerTransitionFormPage,
33    msave, emit_lock_message,
34    StudentActivateView, StudentDeactivateView,
35    ExportPDFTranscriptSlip,
36    PaymentsManageFormPage)
37from waeup.kofa.students.workflow import (CREATED, ADMITTED, PAID,
38    CLEARANCE, REQUESTED, RETURNING, CLEARED, REGISTERED, VALIDATED,
39    GRADUATED, TRANSCRIPT, FORBIDDEN_POSTGRAD_TRANS)
40from waeup.kofa.students.interfaces import IStudentsUtils, ICourseTicket
41from waeup.kofa.students.workflow import FORBIDDEN_POSTGRAD_TRANS
42from kofacustom.nigeria.students.browser import (
43    NigeriaOnlinePaymentDisplayFormPage,
44    NigeriaStudentBaseManageFormPage,
45    NigeriaStudentClearanceEditFormPage,
46    NigeriaOnlinePaymentAddFormPage,
47    NigeriaExportPDFPaymentSlip,
48    NigeriaExportPDFClearanceSlip,
49    NigeriaExportPDFBedTicketSlip,
50    NigeriaStudentPersonalDisplayFormPage,
51    NigeriaStudentPersonalManageFormPage,
52    NigeriaStudentPersonalEditFormPage
53    )
54
55from waeup.uniben.students.interfaces import (
56    ICustomStudent,
57    ICustomStudentOnlinePayment,
58    ICustomStudentStudyCourse,
59    ICustomStudentStudyLevel,
60    ICustomUGStudentClearance,
61    ICustomPGStudentClearance,
62    ICustomStudentPersonal,
63    ICustomStudentPersonalEdit)
64from waeup.uniben.interfaces import MessageFactory as _
65
66class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage):
67    """ Page to view an online payment ticket
68    """
69    grok.context(ICustomStudentOnlinePayment)
70    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
71        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
72    form_fields[
73        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
74    form_fields[
75        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
76
77class CustomStudentClearanceEditFormPage(NigeriaStudentClearanceEditFormPage):
78    """ View to edit student clearance data by student
79    """
80
81    @property
82    def form_fields(self):
83        if self.context.is_postgrad:
84            form_fields = grok.AutoFields(ICustomPGStudentClearance).omit(
85            'clearance_locked', 'nysc_location', 'clr_code', 'officer_comment',
86            'physical_clearance_date')
87        else:
88            form_fields = grok.AutoFields(ICustomUGStudentClearance).omit(
89            'clearance_locked', 'clr_code', 'officer_comment',
90            'physical_clearance_date')
91            form_fields['date_of_birth'].for_display = True
92            form_fields['nationality'].for_display = True
93            form_fields['lga'].for_display = True
94        return form_fields
95
96    def dataNotComplete(self):
97        store = getUtility(IExtFileStore)
98        if not store.getFileByContext(self.context, attr=u'birth_certificate.jpg'):
99            return _('No birth certificate uploaded.')
100        if not store.getFileByContext(self.context, attr=u'ref_let.jpg'):
101            return _('No guarantor/referee letter uploaded.')
102        if not store.getFileByContext(self.context, attr=u'acc_let.jpg'):
103            return _('No acceptance letter uploaded.')
104        if not store.getFileByContext(self.context, attr=u'fst_sit_scan.jpg'):
105            return _('No first sitting result uploaded.')
106        #if not store.getFileByContext(self.context, attr=u'scd_sit_scan.jpg'):
107        #    return _('No second sitting result uploaded.')
108        if not store.getFileByContext(self.context, attr=u'secr_cults.jpg'):
109            return _('No affidavit of non-membership of secret cults uploaded.')
110        return False
111
112class CustomOnlinePaymentAddFormPage(NigeriaOnlinePaymentAddFormPage):
113    """ Page to add an online payment ticket
114    """
115    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).select(
116        'p_category')
117
118class CustomExportPDFPaymentSlip(NigeriaExportPDFPaymentSlip):
119    """Deliver a PDF slip of the context.
120    """
121    grok.context(ICustomStudentOnlinePayment)
122    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
123        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
124    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
125    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
126
127
128class CustomExportPDFClearanceSlip(NigeriaExportPDFClearanceSlip):
129    """Deliver a PDF slip of the context.
130    """
131
132    @property
133    def omit_fields(self):
134        omit_fields = ('password', 'suspended', 'suspended_comment',
135                       'phone', 'adm_code', 'email', 'date_of_birth',
136                       'flash_notice')
137        if self.context.faccode == 'JUPEB':
138            omit_fields += ('faculty', 'department')
139        return omit_fields
140
141    @property
142    def label(self):
143        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
144        line0 = ''
145        if self.context.faccode == 'JUPEB':
146            line0 = 'Joint Universities Preliminary Examinations Board (JUPEB)\n'
147        line1 = translate(_('Clearance Slip of'),
148            'waeup.kofa', target_language=portal_language) \
149            + ' %s' % self.context.display_fullname
150        return '%s%s' % (line0, line1)
151
152    def _sigsInFooter(self):
153        isStudent = getattr(
154            self.request.principal, 'user_type', None) == 'student'
155        if not isStudent and self.context.state in (CLEARED, RETURNING):
156            return (_('Date, Student Signature'),
157                    _('Date, Clearance Officer Signature'),
158                    )
159        return ()
160
161    def render(self):
162        studentview = StudentBasePDFFormPage(self.context.student,
163            self.request, self.omit_fields)
164        students_utils = getUtility(IStudentsUtils)
165        return students_utils.renderPDF(
166            self, 'clearance_slip.pdf',
167            self.context.student, studentview, signatures=self._signatures(),
168            sigs_in_footer=self._sigsInFooter(), show_scans=False,
169            omit_fields=self.omit_fields)
170
171
172class ExportClearanceInvitationSlip(UtilityView, grok.View):
173    """Deliver an invitation letter to physical clearance.
174
175    This form page is available only in Uniben.
176    """
177    grok.context(ICustomStudent)
178    grok.name('clearance_invitation_slip.pdf')
179    grok.require('waeup.viewStudent')
180    prefix = 'form'
181
182    label = u'Invitation Letter for Physical Clearance'
183
184    omit_fields = (
185        'suspended', 'phone', 'email',
186        'adm_code', 'suspended_comment',
187        'date_of_birth', 'current_level',
188        'department', 'current_mode',
189        'entry_session', 'matric_number', 'sex',
190        'flash_notice')
191
192    form_fields = []
193
194    @property
195    def note(self):
196        if self.context.physical_clearance_date:
197            return """
198<br /><br /><br /><br /><font size='12'>
199Dear %s,
200<br /><br /><br />
201You are invited for your physical clearance on:
202<br /><br />
203<strong>%s</strong>.
204<br /><br />
205Please bring along this letter of invitation to the University Main Auditorium
206<br /><br />
207on your clearance date.
208<br /><br /><br />
209Signed,
210<br /><br />
211The Registrar<br />
212</font>
213
214""" % (self.context.display_fullname, self.context.physical_clearance_date)
215        return
216
217
218    def update(self):
219        if self.context.student.state != REQUESTED \
220            or not  self.context.student.physical_clearance_date:
221            self.flash(_('Forbidden'), type="warning")
222            self.redirect(self.url(self.context))
223
224    def render(self):
225        studentview = StudentBasePDFFormPage(self.context.student,
226            self.request, self.omit_fields)
227        students_utils = getUtility(IStudentsUtils)
228        return students_utils.renderPDF(
229            self, 'clearance_invitation_slip',
230            self.context.student, studentview,
231            omit_fields=self.omit_fields,
232            note=self.note)
233
234class ExportExaminationScheduleSlip(UtilityView, grok.View):
235    """Deliver a examination schedule slip.
236
237    This form page is available only in Uniben and AAUE.
238    """
239    grok.context(ICustomStudent)
240    grok.name('examination_schedule_slip.pdf')
241    grok.require('waeup.viewStudent')
242    prefix = 'form'
243
244    label = u'Examination Schedule Slip'
245
246    omit_fields = (
247        'suspended', 'phone', 'email',
248        'adm_code', 'suspended_comment',
249        'date_of_birth', 'current_level',
250        'current_mode',
251        'entry_session',
252        'flash_notice')
253
254    form_fields = []
255
256    @property
257    def note(self):
258        return """
259<br /><br /><br /><br /><font size='12'>
260Your examination date, time and venue is scheduled as follows:
261<br /><br />
262<strong>%s</strong>
263</font>
264
265""" % self.context.flash_notice
266        return
267
268
269    def update(self):
270        if not self.context.flash_notice \
271            or not 'exam' in self.context.flash_notice.lower():
272            self.flash(_('Forbidden'), type="warning")
273            self.redirect(self.url(self.context))
274
275    def render(self):
276        studentview = StudentBasePDFFormPage(self.context.student,
277            self.request, self.omit_fields)
278        students_utils = getUtility(IStudentsUtils)
279        return students_utils.renderPDF(
280            self, 'examination_schedule_slip',
281            self.context.student, studentview,
282            omit_fields=self.omit_fields,
283            note=self.note)
284
285class CustomStudentPersonalDisplayFormPage(
286    NigeriaStudentPersonalDisplayFormPage):
287    """ Page to display student personal data
288    """
289
290    form_fields = grok.AutoFields(ICustomStudentPersonal)
291    form_fields['perm_address'].custom_widget = BytesDisplayWidget
292    form_fields['next_kin_address'].custom_widget = BytesDisplayWidget
293    form_fields[
294        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
295
296class CustomStudentPersonalManageFormPage(
297    NigeriaStudentPersonalManageFormPage):
298    """ Page to manage personal data
299    """
300
301    form_fields = grok.AutoFields(ICustomStudentPersonal)
302    form_fields['personal_updated'].for_display = True
303    form_fields[
304        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
305
306class CstomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage):
307    """ Page to edit personal data
308    """
309    form_fields = grok.AutoFields(
310        ICustomStudentPersonalEdit).omit('personal_updated')
311
312class StudyCourseCOEditFormPage(KofaEditFormPage):
313    """ Page to edit the student study course data by clearance officers.
314
315    This form page is available only in Uniben.
316    """
317    grok.context(ICustomStudentStudyCourse)
318    grok.name('edit_level')
319    grok.require('waeup.clearStudent')
320    label = _('Edit current level')
321    pnav = 4
322    form_fields = grok.AutoFields(
323        ICustomStudentStudyCourse).select('current_level')
324
325    def update(self):
326        if not (self.context.is_current and
327            self.context.student.state == REQUESTED):
328            emit_lock_message(self)
329            return
330        super(StudyCourseCOEditFormPage, self).update()
331        return
332
333    @action(_('Save'), style='primary')
334    def save(self, **data):
335        try:
336            msave(self, **data)
337        except ConstraintNotSatisfied:
338            # The selected level might not exist in certificate
339            self.flash(_('Current level not available for certificate.'))
340            return
341        #notify(grok.ObjectModifiedEvent(self.context.__parent__))
342        return
343
344class CustomStudyLevelEditFormPage(StudyLevelEditFormPage):
345    """ Page to edit the student study level data by students.
346
347    """
348    grok.template('studyleveleditpage')
349
350class CustomStudyLevelDisplayFormPage(StudyLevelDisplayFormPage):
351    """ Page to display student study levels
352    """
353    grok.template('studylevelpage')
354
355class CustomExportPDFCourseRegistrationSlip(
356    ExportPDFCourseRegistrationSlip):
357    """Deliver a PDF slip of the context.
358    """
359
360    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
361        'level_verdict', 'gpa', 'level')
362
363    def update(self):
364        if self.context.student.state != REGISTERED \
365            or self.context.student.current_level != self.context.level:
366            self.flash(_('Forbidden'), type="warning")
367            self.redirect(self.url(self.context))
368
369    @property
370    def tabletitle(self):
371        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
372        tabletitle = []
373        tabletitle.append(translate(_('1st Semester Courses'), 'waeup.kofa',
374            target_language=portal_language))
375        tabletitle.append(translate(_('2nd Semester Courses'), 'waeup.kofa',
376            target_language=portal_language))
377        tabletitle.append(translate(_('Level Courses'), 'waeup.kofa',
378            target_language=portal_language))
379        tabletitle.append(translate(_('1st Trimester Courses'), 'waeup.kofa',
380            target_language=portal_language))
381        tabletitle.append(translate(_('2nd Trimester Courses'), 'waeup.kofa',
382            target_language=portal_language))
383        tabletitle.append(translate(_('3rd Trimester Courses'), 'waeup.kofa',
384            target_language=portal_language))
385        return tabletitle
386
387    def render(self):
388        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
389        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
390        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
391        Dept = translate('Dept.', 'waeup.kofa', target_language=portal_language)
392        Faculty = translate('Faculty', 'waeup.kofa', target_language=portal_language)
393        Cred = translate(_('Credits'), 'waeup.uniben', target_language=portal_language)
394        studentview = StudentBasePDFFormPage(self.context.student,
395            self.request, self.omit_fields)
396        students_utils = getUtility(IStudentsUtils)
397
398        tabledata = []
399        tableheader = []
400        for i in range(1,7):
401            tabledata.append(sorted(
402                [value for value in self.context.values() if value.semester == i],
403                key=lambda value: str(value.semester) + value.code))
404            tableheader.append([(Code,'code', 2.5),
405                             (Title,'title', 5),
406                             (Dept,'dcode', 1.5), (Faculty,'fcode', 1.5),
407                             (Cred, 'credits', 1.5),
408                             ])
409        return students_utils.renderPDF(
410            self, 'course_registration_slip.pdf',
411            self.context.student, studentview,
412            tableheader=tableheader,
413            tabledata=tabledata,
414            omit_fields=self.omit_fields
415            )
416
417class UnibenExportPDFCourseResultSlip(ExportPDFCourseRegistrationSlip):
418    """Deliver a PDF slip of the context.
419    """
420
421    grok.name('course_result_slip.pdf')
422
423    @property
424    def tabletitle(self):
425        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
426        tabletitle = []
427        tabletitle.append(translate(_('1st Semester Courses'), 'waeup.kofa',
428            target_language=portal_language))
429        tabletitle.append(translate(_('2nd Semester Courses'), 'waeup.kofa',
430            target_language=portal_language))
431        tabletitle.append(translate(_('Level Courses'), 'waeup.kofa',
432            target_language=portal_language))
433        tabletitle.append(translate(_('1st Trimester Courses'), 'waeup.kofa',
434            target_language=portal_language))
435        tabletitle.append(translate(_('2nd Trimester Courses'), 'waeup.kofa',
436            target_language=portal_language))
437        tabletitle.append(translate(_('3rd Trimester Courses'), 'waeup.kofa',
438            target_language=portal_language))
439        return tabletitle
440
441    @property
442    def label(self):
443        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
444        lang = self.request.cookies.get('kofa.language', portal_language)
445        level_title = translate(self.context.level_title, 'waeup.kofa',
446            target_language=lang)
447        return translate(_('Course Result Slip'),
448            'waeup.uniben', target_language=portal_language) \
449            + ' %s' % level_title
450
451    def render(self):
452        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
453        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
454        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
455        Dept = translate('Dept.', 'waeup.kofa', target_language=portal_language)
456        Faculty = translate('Faculty', 'waeup.kofa', target_language=portal_language)
457        Cred = translate(_('Credits'), 'waeup.uniben', target_language=portal_language)
458        Grade = translate('Grade', 'waeup.kofa', target_language=portal_language)
459        studentview = StudentBasePDFFormPage(self.context.student,
460            self.request, self.omit_fields)
461        students_utils = getUtility(IStudentsUtils)
462
463        tabledata = []
464        tableheader = []
465        for i in range(1,7):
466            tabledata.append(sorted(
467                [value for value in self.context.values() if value.semester == i],
468                key=lambda value: str(value.semester) + value.code))
469            tableheader.append([(Code,'code', 2.5),
470                             (Title,'title', 5),
471                             (Dept,'dcode', 1.5), (Faculty,'fcode', 1.5),
472                             (Cred, 'credits', 1.5),
473                             (Grade, 'grade', 1.5),
474                             ])
475        return students_utils.renderPDF(
476            self, 'course_registration_slip.pdf',
477            self.context.student, studentview,
478            tableheader=tableheader,
479            tabledata=tabledata,
480            omit_fields=self.omit_fields
481            )
482
483class CustomCourseTicketDisplayFormPage(CourseTicketDisplayFormPage):
484    """ Page to display course tickets
485    """
486    form_fields = grok.AutoFields(ICourseTicket).omit('score')
487
488class CustomStudentActivateView(StudentActivateView):
489    """ Activate student account
490    """
491
492    def update(self):
493        self.context.suspended = False
494        self.context.writeLogMessage(self, 'account activated')
495        history = IObjectHistory(self.context)
496        history.addMessage('Student account activated', user='undisclosed')
497        self.flash(_('Student account has been activated.'))
498        self.redirect(self.url(self.context))
499        return
500
501class CustomStudentDeactivateView(StudentDeactivateView):
502    """ Deactivate student account
503    """
504    def update(self):
505        self.context.suspended = True
506        self.context.writeLogMessage(self, 'account deactivated')
507        history = IObjectHistory(self.context)
508        history.addMessage('Student account deactivated', user='undisclosed')
509        self.flash(_('Student account has been deactivated.'))
510        self.redirect(self.url(self.context))
511        return
512
513class CustomExportPDFTranscriptSlip(ExportPDFTranscriptSlip):
514    """Deliver a PDF slip of the context.
515    """
516
517    def _sigsInFooter(self):
518        isStudent = getattr(
519            self.request.principal, 'user_type', None) == 'student'
520        if not isStudent:
521            return (_('D. R. (Exams & Records)'),_('Current Dean of Faculty'),)
522        return ()
523
524    #def _signatures(self):
525    #    return ([(
526    #        'Current HD<br /> D. R. (Exams & Records)<br /> '
527    #        'For: Registrar')],)
528
529    def render(self):
530        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
531        Term = translate(_('Term'), 'waeup.kofa', target_language=portal_language)
532        Code = translate(_('Code'), 'waeup.kofa', target_language=portal_language)
533        Title = translate(_('Title'), 'waeup.kofa', target_language=portal_language)
534        Cred = translate(_('Credits'), 'waeup.kofa', target_language=portal_language)
535        #Score = translate(_('Score'), 'waeup.kofa', target_language=portal_language)
536        Grade = translate(_('Grade'), 'waeup.kofa', target_language=portal_language)
537        studentview = StudentBasePDFFormPage(self.context.student,
538            self.request, self.omit_fields)
539        students_utils = getUtility(IStudentsUtils)
540
541        tableheader = [(Code,'code', 2.5),
542                         (Title,'title', 8.5),
543                         (Term, 'semester', 1.5),
544                         (Cred, 'credits', 1.5),
545                         #(Score, 'score', 1.5),
546                         (Grade, 'grade', 1.5),
547                         ]
548
549        return students_utils.renderPDFTranscript(
550            self, 'transcript.pdf',
551            self.context.student, studentview,
552            omit_fields=self.omit_fields,
553            tableheader=tableheader,
554            signatures=self._signatures(),
555            sigs_in_footer=self._sigsInFooter(),
556            )
557
558class CustomExportPDFBedTicketSlip(NigeriaExportPDFBedTicketSlip):
559    """Deliver a PDF slip of the context.
560    """
561
562    omit_fields = ('password', 'suspended', 'suspended_comment',
563        'phone', 'adm_code', 'email', 'date_of_birth', 'flash_notice')
564
565    def render(self):
566        studentview = StudentBasePDFFormPage(self.context.student,
567            self.request, self.omit_fields)
568        students_utils = getUtility(IStudentsUtils)
569
570        note = """
571<br /><br /><br /><br /><br /><font size="14">
572Please endeavour to pay your hostel maintenance charge within <br /><br />
5734 days of being allocated a space or else you are deemed to have <br /><br />
574voluntarily forfeited it and it goes back into circulation to be <br /><br />
575available for booking afresh!</font>
576"""
577
578        return students_utils.renderPDF(
579            self, 'bed_allocation_slip.pdf',
580            self.context.student, studentview,
581            omit_fields=self.omit_fields,
582            note=note)
583
584class CustomPaymentsManageFormPage(PaymentsManageFormPage):
585    """ Page to manage the student payments. This manage form page is for
586    both students and students officers. Uniben does not allow students
587    to remove any payment ticket.
588    """
589    @property
590    def manage_payments_allowed(self):
591        return checkPermission('waeup.manageStudent', self.context)
Note: See TracBrowser for help on using the repository browser.