source: main/waeup.aaue/trunk/src/waeup/aaue/students/browser.py @ 13788

Last change on this file since 13788 was 13788, checked in by Henrik Bettermann, 9 years ago

Add title line on pg course registration slip.

  • Property svn:keywords set to Id
File size: 22.0 KB
Line 
1## $Id: browser.py 13788 2016-03-25 05:03:57Z 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.component import getUtility
21from zope.security import checkPermission
22from zope.formlib.textwidgets import BytesDisplayWidget
23from waeup.kofa.browser.layout import UtilityView
24from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
25from waeup.kofa.interfaces import IKofaUtils
26from waeup.kofa.students.interfaces import IStudentsUtils, IStudent
27from waeup.kofa.students.workflow import PAID, REGISTERED
28from waeup.kofa.students.browser import (
29    StartClearancePage,
30    StudentBasePDFFormPage,
31    CourseTicketAddFormPage,
32    StudyLevelDisplayFormPage,
33    ExportPDFTranscriptSlip,
34    ExportPDFAdmissionSlip,
35    BedTicketAddPage,
36    StudentFilesUploadPage,
37    PaymentsManageFormPage,
38    CourseTicketDisplayFormPage,
39    CourseTicketManageFormPage,
40    EditScoresPage
41    )
42from kofacustom.nigeria.students.browser import (
43    NigeriaOnlinePaymentDisplayFormPage,
44    NigeriaOnlinePaymentAddFormPage,
45    NigeriaExportPDFPaymentSlip,
46    NigeriaExportPDFCourseRegistrationSlip,
47    NigeriaExportPDFClearanceSlip,
48    NigeriaStudentPersonalDisplayFormPage,
49    NigeriaStudentPersonalEditFormPage,
50    NigeriaStudentPersonalManageFormPage,
51    NigeriaStudentClearanceEditFormPage,
52    NigeriaAccommodationManageFormPage,
53    )
54from waeup.aaue.students.interfaces import (
55    ICustomStudentOnlinePayment,
56    ICustomStudentStudyLevel,
57    ICustomStudent,
58    ICustomStudentPersonal,
59    ICustomStudentPersonalEdit,
60    ICustomUGStudentClearance,
61    ICustomCourseTicket)
62from waeup.aaue.interswitch.browser import gateway_net_amt
63from waeup.aaue.interfaces import MessageFactory as _
64
65class CustomStudentPersonalDisplayFormPage(NigeriaStudentPersonalDisplayFormPage):
66    """ Page to display student personal data
67    """
68    form_fields = grok.AutoFields(ICustomStudentPersonal)
69    form_fields['perm_address'].custom_widget = BytesDisplayWidget
70    form_fields['father_address'].custom_widget = BytesDisplayWidget
71    form_fields['mother_address'].custom_widget = BytesDisplayWidget
72    form_fields['next_kin_address'].custom_widget = BytesDisplayWidget
73    form_fields[
74        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
75
76class CustomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage):
77    """ Page to edit personal data
78    """
79    form_fields = grok.AutoFields(ICustomStudentPersonalEdit).omit('personal_updated')
80
81class CustomStudentPersonalManageFormPage(NigeriaStudentPersonalManageFormPage):
82    """ Page to edit personal data
83    """
84    form_fields = grok.AutoFields(ICustomStudentPersonal)
85    form_fields['personal_updated'].for_display = True
86    form_fields[
87        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
88
89class CustomStudentClearanceEditFormPage(NigeriaStudentClearanceEditFormPage):
90    """ View to edit student clearance data by student
91    """
92
93    @property
94    def form_fields(self):
95        if self.context.is_postgrad:
96            form_fields = grok.AutoFields(ICustomPGStudentClearance).omit(
97            'clearance_locked', 'nysc_location', 'clr_code', 'officer_comment',
98            'physical_clearance_date')
99        else:
100            form_fields = grok.AutoFields(ICustomUGStudentClearance).omit(
101            'clearance_locked', 'clr_code', 'officer_comment',
102            'physical_clearance_date')
103        return form_fields
104
105class CustomStartClearancePage(StartClearancePage):
106    with_ac = False
107
108    @property
109    def all_required_fields_filled(self):
110        if not self.context.email:
111            return _("Email address is missing."), 'edit_base'
112        if not self.context.phone:
113            return _("Phone number is missing."), 'edit_base'
114        if not self.context.father_name:
115            return _("Personal data form is not properly filled."), 'edit_personal'
116        return
117
118class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage):
119    """ Page to view an online payment ticket
120    """
121    grok.context(ICustomStudentOnlinePayment)
122    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
123        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
124    form_fields[
125        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
126    form_fields[
127        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
128
129class CustomOnlinePaymentAddFormPage(NigeriaOnlinePaymentAddFormPage):
130    """ Page to add an online payment ticket
131    """
132    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).select(
133        'p_category')
134
135class CustomPaymentsManageFormPage(PaymentsManageFormPage):
136    """ Page to manage the student payments.
137
138    This manage form page is for both students and students officers.
139    """
140    @property
141    def manage_payments_allowed(self):
142        return checkPermission('waeup.manageStudent', self.context)
143
144class CustomExportPDFPaymentSlip(NigeriaExportPDFPaymentSlip):
145    """Deliver a PDF slip of the context.
146    """
147    grok.context(ICustomStudentOnlinePayment)
148    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
149        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
150    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
151    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
152
153    @property
154    def note(self):
155        p_session = self.context.p_session
156        try:
157            academic_session = grok.getSite()['configuration'][str(p_session)]
158        except KeyError:
159            academic_session = None
160        text =  '\n\n The Amount Authorized is inclusive of: '
161        if self.context.p_category in ('schoolfee_incl', 'schoolfee_1') \
162            and academic_session:
163            welfare_fee = gateway_net_amt(academic_session.welfare_fee)
164            union_fee = gateway_net_amt(academic_session.union_fee)
165            text += ('School Fee, '
166                     '%s Naira Student Union Dues, '
167                     '%s Naira Student Welfare Assurance Fee and '
168                     % (union_fee, welfare_fee))
169        elif self.context.p_category in (
170            'clearance_incl', 'clearance_medical_incl') and academic_session:
171            matric_gown_fee = gateway_net_amt(academic_session.matric_gown_fee)
172            lapel_fee = gateway_net_amt(academic_session.lapel_fee)
173            text += ('Acceptance Fee, '
174                     '%s Naira Matriculation Gown Fee, '
175                     '%s Naira Lapel/File Fee and '
176                     % (matric_gown_fee, lapel_fee))
177        return text + '250.0 Naira Transaction Charge.'
178
179class CustomStudyLevelDisplayFormPage(StudyLevelDisplayFormPage):
180    """ Page to display student study levels
181    """
182    grok.context(ICustomStudentStudyLevel)
183    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
184        'total_credits', 'gpa', 'level')
185    form_fields[
186        'validation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
187
188class CustomExportPDFCourseRegistrationSlip(
189    NigeriaExportPDFCourseRegistrationSlip):
190    """Deliver a PDF slip of the context.
191    """
192    grok.context(ICustomStudentStudyLevel)
193    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
194        'level_session', 'level_verdict',
195        'validated_by', 'validation_date', 'gpa', 'level')
196
197    omit_fields = ('password', 'suspended', 'suspended_comment',
198        'phone', 'adm_code', 'sex', 'email', 'date_of_birth',
199        'department', 'current_mode', 'current_level', 'flash_notice')
200
201    def update(self):
202        if self.context.student.state != REGISTERED \
203            and self.context.student.current_level == self.context.level:
204            self.flash(_('Forbidden'), type="warning")
205            self.redirect(self.url(self.context))
206
207    @property
208    def label(self):
209        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
210        lang = self.request.cookies.get('kofa.language', portal_language)
211        level_title = translate(self.context.level_title, 'waeup.kofa',
212            target_language=lang)
213        line0 = ''
214        if self.context.student.is_postgrad:
215            line0 = 'SCHOOL OF POSTGRADUATE STUDIES\n'
216        elif self.context.student.current_mode.endswith('_pt'):
217            line0 = 'DIRECTORATE OF PART-TIME DEGREE PROGRAMMES\n'
218        line1 = translate(_('Course Registration Slip'),
219            'waeup.kofa', target_language=portal_language) \
220            + ' %s' % level_title
221        line2 = translate(_('Session'),
222            'waeup.kofa', target_language=portal_language) \
223            + ' %s' % self.context.getSessionString
224        return '%s%s\n%s' % (line0, line1, line2)
225
226    @property
227    def title(self):
228        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
229        return translate(_('Units Registered'), 'waeup.kofa',
230            target_language=portal_language)
231
232    def _signatures(self):
233        if self.context.student.current_mode.endswith('_pt') \
234            or self.context.student.current_mode == 'found':
235            return (
236                [('I have selected the course on the advise of my Head of '
237                 'Department. <br>', _('Student\'s Signature'), '<br>')],
238                [('This student has satisfied the department\'s requirements. '
239                 'I recommend to approve the course registration. <br>',
240                 _('Head of Department\'s Signature'), '<br>')],
241                [('' , _('Principal Assistant Registrar\'s Signature'), '<br>')],
242                [('', _('Director\'s Signature'))]
243                )
244        if self.context.student.current_mode in (
245            'de_ft', 'ug_ft', 'dp_ft', 'transfer'):
246            return ([_('Academic Adviser\'s Signature'),
247                _('Faculty Officer\'s Signature'),
248                _('Student\'s Signature')],)
249
250        if self.context.student.current_mode in ('special_pg_ft', 'special_pg_pt'):
251            return (
252                [('I declare that all items of information supplied above are correct:' ,
253                    _('Student\'s Signature'), '<br>')],
254                [('We approved the above registration:',
255                    _('Major Supervisor (Name / Signature)'), '')],
256                [('', _('Co-Supervisor (Name / Signature)'), '')],
257                [('', _('Head of Department'), '<br>')],
258                [('The student has satisfied the conditions for renewal of '
259                  'registration for graduate school programme in this university:',
260                  _('Secretary <br /> (School of Postgraduate Studies)'), '')],
261                [('', _('Dean <br /> (School of Postgraduate Studies)'), '')],
262                )
263        return None
264
265
266    def render(self):
267        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
268        Sem = translate('Sem.', 'waeup.kofa', target_language=portal_language)
269        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
270        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
271        Cred = translate('Cred.', 'waeup.kofa', target_language=portal_language)
272        Score = translate('Score', 'waeup.kofa', target_language=portal_language)
273        Grade = translate('Grade', 'waeup.kofa', target_language=portal_language)
274        Signature = translate(_('Lecturer\'s Signature'), 'waeup.aaue',
275            target_language=portal_language)
276        studentview = StudentBasePDFFormPage(self.context.student,
277            self.request, self.omit_fields)
278        students_utils = getUtility(IStudentsUtils)
279
280        tabledata = []
281        tableheader = []
282        contenttitle = []
283        for i in range(1,7):
284            tabledata.append(sorted(
285                [value for value in self.context.values() if value.semester == i],
286                key=lambda value: str(value.semester) + value.code))
287            tableheader.append([(Code,'code', 2.0),
288                               (Title,'title', 7),
289                               (Cred, 'credits', 1.5),
290                               (Score, 'score', 1.4),
291                               (Grade, 'grade', 1.4),
292                               (Signature, 'dummy', 3),
293                               ])
294        if len(self.label.split('\n')) == 3:
295            topMargin = 1.9
296        elif len(self.label.split('\n')) == 2:
297            topMargin = 1.7
298        else:
299            topMargin = 1.5
300        return students_utils.renderPDF(
301            self, 'course_registration_slip.pdf',
302            self.context.student, studentview,
303            tableheader=tableheader,
304            tabledata=tabledata,
305            signatures=self._signatures(),
306            topMargin=topMargin,
307            omit_fields=self.omit_fields
308            )
309
310class CustomExportPDFTranscriptSlip(ExportPDFTranscriptSlip):
311    """Deliver a PDF slip of the context.
312    """
313
314    def _sigsInFooter(self):
315        return []
316
317    def _signatures(self):
318        return ([(
319            'Akhimien Felicia O. (MANUPA) <br /> Principal Assistant Registrar  <br /> '
320            'Exams, Records and Data Processing Division <br /> For: Registrar')],)
321
322class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
323    """Deliver a PDF Admission slip.
324    """
325
326    @property
327    def label(self):
328        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
329        return translate(_('e-Admission Slip \n'),
330            'waeup.kofa', target_language=portal_language) \
331            + ' %s' % self.context.display_fullname
332
333class CustomExportPDFClearanceSlip(NigeriaExportPDFClearanceSlip):
334    """Deliver a PDF slip of the context.
335    """
336
337    @property
338    def label(self):
339        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
340        return translate(_('Clearance Slip\n'),
341            'waeup.kofa', target_language=portal_language) \
342            + ' %s' % self.context.display_fullname
343
344class StudentGetMatricNumberPage(UtilityView, grok.View):
345    """ Construct and set the matriculation number.
346    """
347    grok.context(IStudent)
348    grok.name('get_matric_number')
349    grok.require('waeup.viewStudent')
350
351    def update(self):
352        students_utils = getUtility(IStudentsUtils)
353        msg, mnumber = students_utils.setMatricNumber(self.context)
354        if msg:
355            self.flash(msg, type="danger")
356        else:
357            self.flash(_('Matriculation number %s assigned.' % mnumber))
358            self.context.writeLogMessage(self, '%s assigned' % mnumber)
359        self.redirect(self.url(self.context))
360        return
361
362    def render(self):
363        return
364
365class ExportPDFMatricNumberSlip(UtilityView, grok.View):
366    """Deliver a PDF notification slip.
367    """
368    grok.context(ICustomStudent)
369    grok.name('matric_number_slip.pdf')
370    grok.require('waeup.viewStudent')
371    prefix = 'form'
372
373    form_fields = grok.AutoFields(ICustomStudent).select(
374        'student_id', 'matric_number')
375    omit_fields = ('date_of_birth', 'current_level', 'flash_notice')
376
377    @property
378    def title(self):
379        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
380        return translate(_('Matriculation Number'), 'waeup.kofa',
381            target_language=portal_language)
382
383    @property
384    def label(self):
385        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
386        return translate(_('Matriculation Number Slip\n'),
387            'waeup.kofa', target_language=portal_language) \
388            + ' %s' % self.context.display_fullname
389
390    def render(self):
391        if self.context.state not in (PAID,) or not self.context.is_fresh \
392            or not self.context.matric_number:
393            self.flash('Not allowed.', type="danger")
394            self.redirect(self.url(self.context))
395            return
396        students_utils = getUtility(IStudentsUtils)
397        pre_text = _('Congratulations! Your acceptance fee and school fees ' +
398                     'payments have been received and your matriculation ' +
399                     'number generated with details as follows.')
400        return students_utils.renderPDFAdmissionLetter(self,
401            self.context.student, omit_fields=self.omit_fields,
402            pre_text=pre_text, post_text='')
403
404class ExportPersonalDataSlip(UtilityView, grok.View):
405    """Deliver a PDF notification slip.
406    """
407    grok.context(ICustomStudent)
408    grok.name('personal_data_slip.pdf')
409    grok.require('waeup.viewStudent')
410    prefix = 'form'
411    note = None
412
413    form_fields = grok.AutoFields(ICustomStudentPersonal).omit('personal_updated')
414    omit_fields = ('suspended', 'suspended_comment', 'adm_code',
415                   'certificate', 'flash_notice')
416
417    @property
418    def title(self):
419        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
420        return translate(_('Personal Data'), 'waeup.kofa',
421            target_language=portal_language)
422
423    @property
424    def label(self):
425        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
426        return translate(_('Personal Data Slip\n'),
427            'waeup.kofa', target_language=portal_language) \
428            + ' %s' % self.context.display_fullname
429
430    def render(self):
431        studentview = StudentBasePDFFormPage(self.context.student,
432            self.request, self.omit_fields)
433        students_utils = getUtility(IStudentsUtils)
434        return students_utils.renderPDF(self, 'personal_data_slip.pdf',
435            self.context.student, studentview, note=self.note,
436            omit_fields=self.omit_fields)
437
438class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
439    """ Page to manage bed tickets.
440    This manage form page is for both students and students officers.
441    """
442    with_hostel_selection = True
443
444class CustomBedTicketAddPage(BedTicketAddPage):
445    with_ac = False
446
447class CustomStudentFilesUploadPage(StudentFilesUploadPage):
448    """ View to upload files by student. Inherit from same class in
449    base package, not from kofacustom.nigeria which
450    requires that no application slip exists.
451    """
452
453class CustomCourseTicketDisplayFormPage(CourseTicketDisplayFormPage):
454    """ Page to display course tickets
455    """
456    form_fields = grok.AutoFields(ICustomCourseTicket)
457
458class CustomCourseTicketManageFormPage(CourseTicketManageFormPage):
459    """ Page to manage course tickets
460    """
461    form_fields = grok.AutoFields(ICustomCourseTicket)
462    form_fields['title'].for_display = True
463    form_fields['fcode'].for_display = True
464    form_fields['dcode'].for_display = True
465    form_fields['semester'].for_display = True
466    form_fields['passmark'].for_display = True
467    form_fields['credits'].for_display = True
468    form_fields['mandatory'].for_display = False
469    form_fields['automatic'].for_display = True
470    form_fields['carry_over'].for_display = True
471
472class CustomEditScoresPage(EditScoresPage):
473    """Page that filters and lists students.
474    """
475    grok.template('editscorespage')
476
477    def update(self,  *args, **kw):
478        form = self.request.form
479        ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
480        self.current_academic_session = grok.getSite()[
481            'configuration'].current_academic_session
482        if self.context.__parent__.__parent__.score_editing_disabled:
483            self.flash(_('Score editing disabled.'), type="warning")
484            self.redirect(self.url(self.context))
485            return
486        if not self.current_academic_session:
487            self.flash(_('Current academic session not set.'), type="warning")
488            self.redirect(self.url(self.context))
489            return
490        self.tickets = self._searchCatalog(self.current_academic_session)
491        editable_tickets = [
492            ticket for ticket in self.tickets if ticket.editable_by_lecturer]
493        if not self.tickets:
494            self.flash(_('No student found.'), type="warning")
495            self.redirect(self.url(self.context))
496            return
497        if 'UPDATE' in form:
498            tno = 0
499            error = ''
500            if not editable_tickets:
501                return
502            scores = form['scores']
503            cas = form['cas']
504            if isinstance(scores, basestring):
505                scores = [scores]
506            if isinstance(cas, basestring):
507                cas = [cas]
508            for ticket in editable_tickets:
509                ticket_error = False
510                score = ticket.score
511                ca = ticket.ca
512                if scores[tno] == '':
513                    score = None
514                if cas[tno] == '':
515                    ca = None
516                try:
517                    if scores[tno]:
518                        score = int(scores[tno])
519                    if cas[tno]:
520                        ca = int(cas[tno])
521                except ValueError:
522                    error += '%s, ' % ticket.student.display_fullname
523                    ticket_error = True
524                if not ticket_error and ticket.score != score:
525                    ticket.score = score
526                    ticket.student.__parent__.logger.info(
527                        '%s - %s %s/%s score updated (%s)' %
528                        (ob_class, ticket.student.student_id,
529                         ticket.level, ticket.code, score))
530                if not ticket_error and ticket.ca != ca:
531                    ticket.ca = ca
532                    ticket.student.__parent__.logger.info(
533                        '%s - %s %s/%s ca updated (%s)' %
534                        (ob_class, ticket.student.student_id,
535                         ticket.level, ticket.code, ca))
536                tno += 1
537            if error:
538                self.flash(_('Error: Score(s) and CA(s) of %s have not be updated. '
539                  'Only integers are allowed.' % error.strip(', ')),
540                  type="danger")
541        return
Note: See TracBrowser for help on using the repository browser.