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

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

Customize NigeriaExportPDFFinancialClearancePage. Students must not see signature box.

  • Property svn:keywords set to Id
File size: 31.2 KB
RevLine 
[8911]1## $Id: browser.py 14137 2016-08-29 06:25:37Z 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
[13937]19import csv
[13964]20import textwrap
[13937]21from cStringIO import StringIO
[8911]22from zope.i18n import translate
[13900]23from zope.component import getUtility, queryUtility
[14113]24from zope.schema.interfaces import TooBig, TooSmall
[13523]25from zope.security import checkPermission
[13900]26from zope.catalog.interfaces import ICatalog
[13351]27from zope.formlib.textwidgets import BytesDisplayWidget
[11597]28from waeup.kofa.browser.layout import UtilityView
[8911]29from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
[13939]30from waeup.kofa.interfaces import IKofaUtils, academic_sessions_vocab
[11597]31from waeup.kofa.students.interfaces import IStudentsUtils, IStudent
[14000]32from waeup.kofa.students.workflow import PAID, REGISTERED, RETURNING
[13964]33from waeup.kofa.students.studylevel import getGradeWeightFromScore
[9914]34from waeup.kofa.students.browser import (
[11846]35    StartClearancePage,
[9914]36    StudentBasePDFFormPage,
37    CourseTicketAddFormPage,
38    StudyLevelDisplayFormPage,
[13834]39    StudyLevelManageFormPage,
40    StudyLevelEditFormPage,
[13059]41    ExportPDFTranscriptSlip,
42    ExportPDFAdmissionSlip,
[13353]43    BedTicketAddPage,
[13380]44    StudentFilesUploadPage,
[13523]45    PaymentsManageFormPage,
[13770]46    CourseTicketDisplayFormPage,
47    CourseTicketManageFormPage,
[13900]48    EditScoresPage,
49    ExportPDFScoresSlip
[10269]50    )
[8911]51from kofacustom.nigeria.students.browser import (
52    NigeriaOnlinePaymentDisplayFormPage,
53    NigeriaOnlinePaymentAddFormPage,
[13059]54    NigeriaExportPDFPaymentSlip,
55    NigeriaExportPDFCourseRegistrationSlip,
[13351]56    NigeriaStudentPersonalDisplayFormPage,
57    NigeriaStudentPersonalEditFormPage,
58    NigeriaStudentPersonalManageFormPage,
[14084]59    NigeriaStudentClearanceDisplayFormPage,
60    NigeriaExportPDFClearanceSlip,
61    NigeriaStudentClearanceManageFormPage,
[13362]62    NigeriaStudentClearanceEditFormPage,
[13462]63    NigeriaAccommodationManageFormPage,
[13795]64    NigeriaStudentBaseDisplayFormPage,
[14137]65    NigeriaStudentBaseManageFormPage,
66    NigeriaExportPDFFinancialClearancePage
[10269]67    )
[9496]68from waeup.aaue.students.interfaces import (
[9914]69    ICustomStudentOnlinePayment,
[11607]70    ICustomStudentStudyLevel,
[13351]71    ICustomStudent,
72    ICustomStudentPersonal,
[13362]73    ICustomStudentPersonalEdit,
[13770]74    ICustomUGStudentClearance,
[14084]75    ICustomPGStudentClearance,
[13795]76    ICustomCourseTicket,
77    ICustomStudentBase)
[13414]78from waeup.aaue.interswitch.browser import gateway_net_amt
[9914]79from waeup.aaue.interfaces import MessageFactory as _
[8911]80
[13795]81class CustomStudentBaseDisplayFormPage(NigeriaStudentBaseDisplayFormPage):
82    """ Page to display student base data
83    """
84    form_fields = grok.AutoFields(ICustomStudentBase).omit(
85        'password', 'suspended', 'suspended_comment', 'flash_notice')
86    form_fields[
87        'financial_clearance_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
88
89class CustomStudentBaseManageFormPage(NigeriaStudentBaseManageFormPage):
90    """ View to manage student base data
91    """
92    form_fields = grok.AutoFields(ICustomStudentBase).omit(
93        'student_id', 'adm_code', 'suspended',
94        'financially_cleared_by', 'financial_clearance_date')
95
[13351]96class CustomStudentPersonalDisplayFormPage(NigeriaStudentPersonalDisplayFormPage):
97    """ Page to display student personal data
98    """
99    form_fields = grok.AutoFields(ICustomStudentPersonal)
100    form_fields['perm_address'].custom_widget = BytesDisplayWidget
101    form_fields['father_address'].custom_widget = BytesDisplayWidget
102    form_fields['mother_address'].custom_widget = BytesDisplayWidget
103    form_fields['next_kin_address'].custom_widget = BytesDisplayWidget
104    form_fields[
105        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
106
107class CustomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage):
108    """ Page to edit personal data
109    """
110    form_fields = grok.AutoFields(ICustomStudentPersonalEdit).omit('personal_updated')
111
112class CustomStudentPersonalManageFormPage(NigeriaStudentPersonalManageFormPage):
113    """ Page to edit personal data
114    """
115    form_fields = grok.AutoFields(ICustomStudentPersonal)
116    form_fields['personal_updated'].for_display = True
117    form_fields[
118        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
119
[14084]120class CustomStudentClearanceDisplayFormPage(NigeriaStudentClearanceDisplayFormPage):
121    """ Page to display student clearance data
122    """
123
124    @property
125    def form_fields(self):
126        if self.context.is_postgrad:
127            form_fields = grok.AutoFields(
128                ICustomPGStudentClearance).omit('clearance_locked')
129        else:
130            form_fields = grok.AutoFields(
131                ICustomUGStudentClearance).omit('clearance_locked')
132        if not getattr(self.context, 'officer_comment'):
133            form_fields = form_fields.omit('officer_comment')
134        else:
135            form_fields['officer_comment'].custom_widget = BytesDisplayWidget
[14104]136        form_fields = form_fields.omit('def_adm')
[14084]137        return form_fields
138
139class CustomStudentClearanceManageFormPage(NigeriaStudentClearanceManageFormPage):
140    """ Page to edit student clearance data
141    """
142
143    @property
144    def form_fields(self):
145        if self.context.is_postgrad:
146            form_fields = grok.AutoFields(
147                ICustomPGStudentClearance).omit('clr_code')
148        else:
149            form_fields = grok.AutoFields(
150                ICustomUGStudentClearance).omit('clr_code')
[14104]151        form_fields = form_fields.omit('def_adm')
[14084]152        return form_fields
153
[13362]154class CustomStudentClearanceEditFormPage(NigeriaStudentClearanceEditFormPage):
155    """ View to edit student clearance data by student
156    """
157
158    @property
159    def form_fields(self):
160        if self.context.is_postgrad:
161            form_fields = grok.AutoFields(ICustomPGStudentClearance).omit(
162            'clearance_locked', 'nysc_location', 'clr_code', 'officer_comment',
163            'physical_clearance_date')
164        else:
165            form_fields = grok.AutoFields(ICustomUGStudentClearance).omit(
166            'clearance_locked', 'clr_code', 'officer_comment',
[14104]167            'physical_clearance_date', 'date_of_birth', 'nationality', 'lga')
168        form_fields = form_fields.omit('def_adm')
[13362]169        return form_fields
170
[11846]171class CustomStartClearancePage(StartClearancePage):
[13360]172    with_ac = False
[11846]173
[13351]174    @property
175    def all_required_fields_filled(self):
176        if not self.context.email:
177            return _("Email address is missing."), 'edit_base'
178        if not self.context.phone:
179            return _("Phone number is missing."), 'edit_base'
180        if not self.context.father_name:
181            return _("Personal data form is not properly filled."), 'edit_personal'
182        return
183
[8911]184class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage):
185    """ Page to view an online payment ticket
186    """
187    grok.context(ICustomStudentOnlinePayment)
[9853]188    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
[9990]189        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
[8911]190    form_fields[
191        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
192    form_fields[
193        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
194
195class CustomOnlinePaymentAddFormPage(NigeriaOnlinePaymentAddFormPage):
196    """ Page to add an online payment ticket
197    """
198    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).select(
199        'p_category')
200
[13523]201class CustomPaymentsManageFormPage(PaymentsManageFormPage):
202    """ Page to manage the student payments.
203
204    This manage form page is for both students and students officers.
205    """
206    @property
207    def manage_payments_allowed(self):
208        return checkPermission('waeup.manageStudent', self.context)
209
[13059]210class CustomExportPDFPaymentSlip(NigeriaExportPDFPaymentSlip):
[8911]211    """Deliver a PDF slip of the context.
212    """
213    grok.context(ICustomStudentOnlinePayment)
[9853]214    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
[9990]215        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
[8911]216    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
[9496]217    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
[9914]218
[11625]219    @property
220    def note(self):
[13408]221        p_session = self.context.p_session
[13405]222        try:
[13408]223            academic_session = grok.getSite()['configuration'][str(p_session)]
[13405]224        except KeyError:
225            academic_session = None
[13425]226        text =  '\n\n The Amount Authorized is inclusive of: '
[13512]227        if self.context.p_category in ('schoolfee_incl', 'schoolfee_1') \
228            and academic_session:
[13414]229            welfare_fee = gateway_net_amt(academic_session.welfare_fee)
230            union_fee = gateway_net_amt(academic_session.union_fee)
[13437]231            text += ('School Fee, '
[13463]232                     '%s Naira Student Union Dues, '
[13437]233                     '%s Naira Student Welfare Assurance Fee and '
[13425]234                     % (union_fee, welfare_fee))
[13410]235        elif self.context.p_category in (
236            'clearance_incl', 'clearance_medical_incl') and academic_session:
[13414]237            matric_gown_fee = gateway_net_amt(academic_session.matric_gown_fee)
238            lapel_fee = gateway_net_amt(academic_session.lapel_fee)
[13437]239            text += ('Acceptance Fee, '
240                     '%s Naira Matriculation Gown Fee, '
241                     '%s Naira Lapel/File Fee and '
[13408]242                     % (matric_gown_fee, lapel_fee))
[13437]243        return text + '250.0 Naira Transaction Charge.'
[11625]244
[9914]245class CustomStudyLevelDisplayFormPage(StudyLevelDisplayFormPage):
246    """ Page to display student study levels
247    """
248    grok.context(ICustomStudentStudyLevel)
[10480]249    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
[12876]250        'total_credits', 'gpa', 'level')
[9914]251    form_fields[
252        'validation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
253
[14000]254    @property
255    def show_results(self):
256        isStudent = getattr(
257            self.request.principal, 'user_type', None) == 'student'
258        if isStudent and self.context.student.state != RETURNING \
259            and self.context.student.current_level == self.context.level:
260            return False
261        return True
262
[13834]263class CustomStudyLevelManageFormPage(StudyLevelManageFormPage):
264    """ Page to edit the student study level data
265    """
266    grok.context(ICustomStudentStudyLevel)
267
268class CustomStudyLevelEditFormPage(StudyLevelEditFormPage):
269    """ Page to edit the student study level data by students
270    """
271    grok.context(ICustomStudentStudyLevel)
272
[13059]273class CustomExportPDFCourseRegistrationSlip(
274    NigeriaExportPDFCourseRegistrationSlip):
[9914]275    """Deliver a PDF slip of the context.
276    """
277    grok.context(ICustomStudentStudyLevel)
278    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
[10102]279        'level_session', 'level_verdict',
[12876]280        'validated_by', 'validation_date', 'gpa', 'level')
[9914]281
[10269]282    omit_fields = ('password', 'suspended', 'suspended_comment',
[10689]283        'phone', 'adm_code', 'sex', 'email', 'date_of_birth',
[13713]284        'department', 'current_mode', 'current_level', 'flash_notice')
[10269]285
[14000]286    @property
287    def show_results(self):
288        isStudent = getattr(
289            self.request.principal, 'user_type', None) == 'student'
290        return not isStudent \
291            or self.context.student.current_level != self.context.level \
292            or self.context.student.state == RETURNING
293
[13038]294    def update(self):
295        if self.context.student.state != REGISTERED \
[13051]296            and self.context.student.current_level == self.context.level:
[13038]297            self.flash(_('Forbidden'), type="warning")
298            self.redirect(self.url(self.context))
[14000]299            return
[13038]300
[9914]301    @property
302    def label(self):
303        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
304        lang = self.request.cookies.get('kofa.language', portal_language)
305        level_title = translate(self.context.level_title, 'waeup.kofa',
306            target_language=lang)
307        line0 = ''
[13788]308        if self.context.student.is_postgrad:
309            line0 = 'SCHOOL OF POSTGRADUATE STUDIES\n'
310        elif self.context.student.current_mode.endswith('_pt'):
[9914]311            line0 = 'DIRECTORATE OF PART-TIME DEGREE PROGRAMMES\n'
[13866]312        line1 = translate(_('Course Registration Slip'),
313            target_language=portal_language) \
[9914]314            + ' %s' % level_title
[13866]315        line2 = translate(_('Session'),
316            target_language=portal_language) \
[9914]317            + ' %s' % self.context.getSessionString
318        return '%s%s\n%s' % (line0, line1, line2)
319
320    @property
321    def title(self):
322        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]323        return translate(_('Units Registered'), target_language=portal_language)
[9914]324
325    def _signatures(self):
[13647]326        if self.context.student.current_mode.endswith('_pt') \
327            or self.context.student.current_mode == 'found':
328            return (
329                [('I have selected the course on the advise of my Head of '
330                 'Department. <br>', _('Student\'s Signature'), '<br>')],
331                [('This student has satisfied the department\'s requirements. '
332                 'I recommend to approve the course registration. <br>',
333                 _('Head of Department\'s Signature'), '<br>')],
[13946]334                [('' , _('Deputy Registrar\'s Signature'), '<br>')],
[13647]335                [('', _('Director\'s Signature'))]
336                )
337        if self.context.student.current_mode in (
338            'de_ft', 'ug_ft', 'dp_ft', 'transfer'):
[13649]339            return ([_('Academic Adviser\'s Signature'),
340                _('Faculty Officer\'s Signature'),
341                _('Student\'s Signature')],)
342
[13647]343        if self.context.student.current_mode in ('special_pg_ft', 'special_pg_pt'):
344            return (
[13676]345                [('I declare that all items of information supplied above are correct:' ,
[13680]346                    _('Student\'s Signature'), '<br>')],
[13676]347                [('We approved the above registration:',
[13680]348                    _('Major Supervisor (Name / Signature)'), '')],
349                [('', _('Co-Supervisor (Name / Signature)'), '')],
[13676]350                [('', _('Head of Department'), '<br>')],
351                [('The student has satisfied the conditions for renewal of '
352                  'registration for graduate school programme in this university:',
[13680]353                  _('Secretary <br /> (School of Postgraduate Studies)'), '')],
354                [('', _('Dean <br /> (School of Postgraduate Studies)'), '')],
[13647]355                )
356        return None
[9914]357
[13647]358
[9914]359    def render(self):
360        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]361        Sem = translate(_('Sem.'), target_language=portal_language)
362        Code = translate(_('Code'), target_language=portal_language)
363        Title = translate(_('Title'), target_language=portal_language)
364        Cred = translate(_('Cred.'), target_language=portal_language)
[14000]365        if self.show_results:
366            Score = translate(_('Score'), target_language=portal_language)
367            #CA = translate(_('CA'), target_language=portal_language)
368            Grade = translate(_('Grade'), target_language=portal_language)
[13866]369        Signature = translate(_('Lecturer\'s Signature'), 'waeup.aaue',
[9914]370            target_language=portal_language)
371        studentview = StudentBasePDFFormPage(self.context.student,
372            self.request, self.omit_fields)
373        students_utils = getUtility(IStudentsUtils)
[10442]374
375        tabledata = []
376        tableheader = []
377        contenttitle = []
378        for i in range(1,7):
379            tabledata.append(sorted(
380                [value for value in self.context.values() if value.semester == i],
381                key=lambda value: str(value.semester) + value.code))
[14000]382            if self.show_results:
383                tableheader.append([(Code,'code', 2.0),
384                                   (Title,'title', 7),
385                                   (Cred, 'credits', 1.5),
386                                   (Score, 'score', 1.4),
387                                   #(CA, 'ca', 1.4),
388                                   (Grade, 'grade', 1.4),
389                                   (Signature, 'dummy', 3),
390                                   ])
391            else:
392                tableheader.append([(Code,'code', 2.0),
393                                   (Title,'title', 7),
394                                   (Cred, 'credits', 1.5),
395                                   (Signature, 'dummy', 3),
396                                   ])
[9914]397        if len(self.label.split('\n')) == 3:
398            topMargin = 1.9
399        elif len(self.label.split('\n')) == 2:
400            topMargin = 1.7
401        else:
402            topMargin = 1.5
403        return students_utils.renderPDF(
404            self, 'course_registration_slip.pdf',
405            self.context.student, studentview,
[10442]406            tableheader=tableheader,
407            tabledata=tabledata,
[9914]408            signatures=self._signatures(),
[10269]409            topMargin=topMargin,
410            omit_fields=self.omit_fields
[9914]411            )
[10566]412
[13059]413class CustomExportPDFTranscriptSlip(ExportPDFTranscriptSlip):
[10566]414    """Deliver a PDF slip of the context.
415    """
416
417    def _sigsInFooter(self):
418        return []
419
420    def _signatures(self):
421        return ([(
[14136]422            'Mrs. Uniamikogbo, S.O., mnim, manupa <br /> Prin. Asst Registrar  <br /> '
[11555]423            'Exams, Records and Data Processing Division <br /> For: Registrar')],)
[10922]424
[13834]425    def render(self):
426        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]427        Term = translate(_('Sem.'), target_language=portal_language)
428        Code = translate(_('Code'), target_language=portal_language)
429        Title = translate(_('Title'), target_language=portal_language)
430        Cred = translate(_('Credits'), target_language=portal_language)
431        Score = translate(_('Score'), target_language=portal_language)
432        Grade = translate(_('Grade'), target_language=portal_language)
[13834]433        studentview = StudentBasePDFFormPage(self.context.student,
434            self.request, self.omit_fields)
435        students_utils = getUtility(IStudentsUtils)
436
437        tableheader = [(Code,'code', 2.5),
438                         (Title,'title', 7),
439                         (Term, 'semester', 1.5),
440                         (Cred, 'credits', 1.5),
[14136]441                         (Score, 'total_score', 1.5),
[13834]442                         (Grade, 'grade', 1.5),
443                         ]
444
445        return students_utils.renderPDFTranscript(
446            self, 'transcript.pdf',
447            self.context.student, studentview,
448            omit_fields=self.omit_fields,
449            tableheader=tableheader,
450            signatures=self._signatures(),
451            sigs_in_footer=self._sigsInFooter(),
452            )
453
[13059]454class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
[10922]455    """Deliver a PDF Admission slip.
456    """
457
458    @property
459    def label(self):
460        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]461        return translate(_('e-Admission Slip \n'),
462            target_language=portal_language) \
[10922]463            + ' %s' % self.context.display_fullname
[11597]464
[13059]465class CustomExportPDFClearanceSlip(NigeriaExportPDFClearanceSlip):
[11606]466    """Deliver a PDF slip of the context.
467    """
468
469    @property
470    def label(self):
471        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[14114]472        return translate(_('Verification/Clearance Slip\n'),
[13866]473            target_language=portal_language) \
[11606]474            + ' %s' % self.context.display_fullname
475
[14084]476    @property
477    def form_fields(self):
478        if self.context.is_postgrad:
479            form_fields = grok.AutoFields(
480                ICustomPGStudentClearance).omit('clearance_locked')
481        else:
482            form_fields = grok.AutoFields(
483                ICustomUGStudentClearance).omit('clearance_locked')
484        if not getattr(self.context, 'officer_comment'):
485            form_fields = form_fields.omit('officer_comment')
[14104]486        form_fields = form_fields.omit('def_adm')
[14084]487        return form_fields
488
[11597]489class StudentGetMatricNumberPage(UtilityView, grok.View):
490    """ Construct and set the matriculation number.
491    """
492    grok.context(IStudent)
493    grok.name('get_matric_number')
494    grok.require('waeup.viewStudent')
495
496    def update(self):
497        students_utils = getUtility(IStudentsUtils)
498        msg, mnumber = students_utils.setMatricNumber(self.context)
499        if msg:
500            self.flash(msg, type="danger")
501        else:
502            self.flash(_('Matriculation number %s assigned.' % mnumber))
[11602]503            self.context.writeLogMessage(self, '%s assigned' % mnumber)
[11597]504        self.redirect(self.url(self.context))
505        return
506
507    def render(self):
[11607]508        return
509
[13059]510class ExportPDFMatricNumberSlip(UtilityView, grok.View):
[11607]511    """Deliver a PDF notification slip.
512    """
513    grok.context(ICustomStudent)
514    grok.name('matric_number_slip.pdf')
515    grok.require('waeup.viewStudent')
516    prefix = 'form'
517
518    form_fields = grok.AutoFields(ICustomStudent).select(
519        'student_id', 'matric_number')
[13713]520    omit_fields = ('date_of_birth', 'current_level', 'flash_notice')
[11607]521
522    @property
[13489]523    def title(self):
524        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]525        return translate(_('Matriculation Number'), 'waeup.kofa',
[13489]526            target_language=portal_language)
527
528    @property
[11607]529    def label(self):
530        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]531        return translate(_('Matriculation Number Slip\n'),
532            target_language=portal_language) \
[11607]533            + ' %s' % self.context.display_fullname
534
535    def render(self):
536        if self.context.state not in (PAID,) or not self.context.is_fresh \
537            or not self.context.matric_number:
538            self.flash('Not allowed.', type="danger")
539            self.redirect(self.url(self.context))
540            return
541        students_utils = getUtility(IStudentsUtils)
[11609]542        pre_text = _('Congratulations! Your acceptance fee and school fees ' +
543                     'payments have been received and your matriculation ' +
544                     'number generated with details as follows.')
[11607]545        return students_utils.renderPDFAdmissionLetter(self,
546            self.context.student, omit_fields=self.omit_fields,
[13353]547            pre_text=pre_text, post_text='')
548
[13489]549class ExportPersonalDataSlip(UtilityView, grok.View):
550    """Deliver a PDF notification slip.
551    """
552    grok.context(ICustomStudent)
553    grok.name('personal_data_slip.pdf')
554    grok.require('waeup.viewStudent')
555    prefix = 'form'
556    note = None
557
558    form_fields = grok.AutoFields(ICustomStudentPersonal).omit('personal_updated')
[13713]559    omit_fields = ('suspended', 'suspended_comment', 'adm_code',
560                   'certificate', 'flash_notice')
[13489]561
562    @property
563    def title(self):
564        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]565        return translate(_('Personal Data'), 'waeup.kofa',
[13489]566            target_language=portal_language)
567
568    @property
569    def label(self):
570        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]571        return translate(_('Personal Data Slip\n'),
572            target_language=portal_language) \
[13489]573            + ' %s' % self.context.display_fullname
574
575    def render(self):
576        studentview = StudentBasePDFFormPage(self.context.student,
577            self.request, self.omit_fields)
578        students_utils = getUtility(IStudentsUtils)
579        return students_utils.renderPDF(self, 'personal_data_slip.pdf',
580            self.context.student, studentview, note=self.note,
581            omit_fields=self.omit_fields)
582
[13462]583class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
584    """ Page to manage bed tickets.
585    This manage form page is for both students and students officers.
586    """
587    with_hostel_selection = True
588
[13353]589class CustomBedTicketAddPage(BedTicketAddPage):
[13360]590    with_ac = False
[13380]591
592class CustomStudentFilesUploadPage(StudentFilesUploadPage):
593    """ View to upload files by student. Inherit from same class in
594    base package, not from kofacustom.nigeria which
595    requires that no application slip exists.
[13770]596    """
597
598class CustomCourseTicketDisplayFormPage(CourseTicketDisplayFormPage):
599    """ Page to display course tickets
600    """
601    form_fields = grok.AutoFields(ICustomCourseTicket)
602
603class CustomCourseTicketManageFormPage(CourseTicketManageFormPage):
604    """ Page to manage course tickets
605    """
606    form_fields = grok.AutoFields(ICustomCourseTicket)
607    form_fields['title'].for_display = True
608    form_fields['fcode'].for_display = True
609    form_fields['dcode'].for_display = True
610    form_fields['semester'].for_display = True
611    form_fields['passmark'].for_display = True
612    form_fields['credits'].for_display = True
613    form_fields['mandatory'].for_display = False
614    form_fields['automatic'].for_display = True
615    form_fields['carry_over'].for_display = True
616
617class CustomEditScoresPage(EditScoresPage):
618    """Page that filters and lists students.
619    """
620    grok.template('editscorespage')
621
[13937]622
623    def _extract_uploadfile(self, uploadfile):
624        """Get a mapping of student-ids to scores.
625
626        The mapping is constructed by reading contents from `uploadfile`.
627
628        We expect uploadfile to be a regular CSV file with columns
629        ``student_id``, ``score`` and ``ca`` (other cols are ignored).
630        """
631        result = dict()
632        data = StringIO(uploadfile.read())  # ensure we have something seekable
633        reader = csv.DictReader(data)
634        for row in reader:
635            if not ('student_id' in row and 'score' in row and 'ca' in row):
636                continue
637            result[row['student_id']] = (row['score'], row['ca'])
638        return result
639
[13770]640    def update(self,  *args, **kw):
641        form = self.request.form
[13937]642        ob_class = self.__implemented__.__name__.replace('waeup.kofa.', '')
[13770]643        self.current_academic_session = grok.getSite()[
644            'configuration'].current_academic_session
645        if self.context.__parent__.__parent__.score_editing_disabled:
646            self.flash(_('Score editing disabled.'), type="warning")
647            self.redirect(self.url(self.context))
648            return
649        if not self.current_academic_session:
650            self.flash(_('Current academic session not set.'), type="warning")
651            self.redirect(self.url(self.context))
652            return
[13939]653        self.session_title = academic_sessions_vocab.getTerm(
654            self.current_academic_session).title
[13770]655        self.tickets = self._searchCatalog(self.current_academic_session)
656        editable_tickets = [
657            ticket for ticket in self.tickets if ticket.editable_by_lecturer]
658        if not self.tickets:
659            self.flash(_('No student found.'), type="warning")
660            self.redirect(self.url(self.context))
661            return
[13937]662        if not 'UPDATE_TABLE' in form and not 'UPDATE_FILE' in form:
663            return
664
665        if not editable_tickets:
666            return
667        if 'UPDATE_FILE' in form:
668            if form['uploadfile']:
669                try:
670                    formvals = self._extract_uploadfile(form['uploadfile'])
671                except:
672                    self.flash(
673                        _('Uploaded file contains illegal data. Ignored'),
674                        type="danger")
675                    return
676            else:
677                self.flash(
678                    _('No file provided.'), type="danger")
[13770]679                return
[13937]680        else:
681            formvals = dict(zip(form['sids'], zip(form['scores'], form['cas'])))
682        error = ''
683        for ticket in editable_tickets:
684            ticket_error = False
685            score = ticket.score
686            ca = ticket.ca
687            sid = ticket.student.student_id
688            if formvals[sid][0] == '':
689                score = None
690            if formvals[sid][1] == '':
691                ca = None
692            try:
693                if formvals[sid][0]:
694                    score = int(formvals[sid][0])
695                if formvals[sid][1]:
696                    ca = int(formvals[sid][1])
697            except ValueError:
698                error += '%s, ' % ticket.student.display_fullname
699                ticket_error = True
700            if not ticket_error and ticket.score != score:
[14113]701                try:
702                    ticket.score = score
703                except TooBig:
704                    error += '%s, ' % ticket.student.display_fullname
705                    ticket_error = True
706                    pass
[13937]707                ticket.student.__parent__.logger.info(
708                    '%s - %s %s/%s score updated (%s)' %
709                    (ob_class, ticket.student.student_id,
710                     ticket.level, ticket.code, score))
711            if not ticket_error and ticket.ca != ca:
[14113]712                try:
713                    ticket.ca = ca
714                except TooBig:
715                    error += '%s, ' % ticket.student.display_fullname
716                    pass
[13937]717                ticket.student.__parent__.logger.info(
718                    '%s - %s %s/%s ca updated (%s)' %
719                    (ob_class, ticket.student.student_id,
720                     ticket.level, ticket.code, ca))
721        if error:
722            self.flash(_('Error: Score(s) and CA(s) of %s have not be updated. '
[14113]723              % error.strip(', ')), type="danger")
[13939]724            return
725        self.flash(_('You successfully updated course results.'))
[13900]726        return
727
728class CustomExportPDFScoresSlip(ExportPDFScoresSlip):
729    """Deliver a PDF slip of course tickets for a lecturer.
730    """
731
732    def table_data(self, session):
733        cat = queryUtility(ICatalog, name='coursetickets_catalog')
734        coursetickets = cat.searchResults(
735            session=(session, session),
736            code=(self.context.code, self.context.code)
737            )
[13963]738        header = [[_(''),
739                   _('Matric No.'),
[13900]740                   _('Reg. No.'),
741                   _('Fullname'),
742                   _('Status'),
[13963]743                   _('Course of\nStudies'),
[13900]744                   _('Level'),
[13963]745                   _('Exam\nScore'),
[13964]746                   _(' CA  '),
747                   _('Total '),
[13963]748                   _('Grade'),
749                   ],]
[13907]750        tickets = []
[13963]751        no = 1
[13900]752        for ticket in list(coursetickets):
[13963]753            if None in (ticket.score, ticket.ca):
754                total = 'n/a'
[13964]755                grade = 'n/a'
[13963]756            else:
757                total = ticket.score + ticket.ca
[13964]758                grade = getGradeWeightFromScore(total)[0]
759            fullname = textwrap.fill(ticket.student.display_fullname, 30)
[13963]760            row = [no,
761                  ticket.student.matric_number,
[13900]762                  ticket.student.reg_number,
[13964]763                  fullname,
[13900]764                  ticket.student.translated_state,
765                  ticket.student.certcode,
766                  ticket.level,
[13963]767                  ticket.ca,
[13900]768                  ticket.score,
[13963]769                  total,
[13964]770                  grade,
[13963]771                  ]
[13907]772            tickets.append(row)
[13963]773            no += 1
[13997]774        return header + sorted(tickets,
[14068]775            key=lambda value: value[5] + value[3] + str(value[6]))
[13907]776
[14137]777
778
779class CustomExportPDFFinancialClearancePage(NigeriaExportPDFFinancialClearancePage):
780    """Deliver a PDF financial clearance slip.
781    """
782
783    def _sigsInFooter(self):
784        if not checkPermission('waeup.clearStudentFinancially', self.context):
785            return ()
786        return (_('Date, Checking Officer Signature'),
787                _('Date, Approving Officer Signature'),
788                )
Note: See TracBrowser for help on using the repository browser.