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

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

Remove CustomStudyCourseTranscriptPage?.

Students are allowed to view transcripts. Buttons not yet visible, waiting for confirmation.

  • Property svn:keywords set to Id
File size: 31.3 KB
RevLine 
[8911]1## $Id: browser.py 14165 2016-09-06 18:37:59Z 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,
[14165]49    ExportPDFScoresSlip,
50    StudyCourseTranscriptPage,
[10269]51    )
[8911]52from kofacustom.nigeria.students.browser import (
53    NigeriaOnlinePaymentDisplayFormPage,
54    NigeriaOnlinePaymentAddFormPage,
[13059]55    NigeriaExportPDFPaymentSlip,
56    NigeriaExportPDFCourseRegistrationSlip,
[13351]57    NigeriaStudentPersonalDisplayFormPage,
58    NigeriaStudentPersonalEditFormPage,
59    NigeriaStudentPersonalManageFormPage,
[14084]60    NigeriaStudentClearanceDisplayFormPage,
61    NigeriaExportPDFClearanceSlip,
62    NigeriaStudentClearanceManageFormPage,
[13362]63    NigeriaStudentClearanceEditFormPage,
[13462]64    NigeriaAccommodationManageFormPage,
[13795]65    NigeriaStudentBaseDisplayFormPage,
[14165]66    NigeriaStudentBaseManageFormPage
[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
[14165]413class CustomStudyCourseTranscriptPage(StudyCourseTranscriptPage):
414    """ Page to display the student's transcript.
415    """
416    grok.require('waeup.viewStudent')
417
[13059]418class CustomExportPDFTranscriptSlip(ExportPDFTranscriptSlip):
[10566]419    """Deliver a PDF slip of the context.
420    """
[14165]421    grok.require('waeup.viewStudent')
[10566]422
423    def _sigsInFooter(self):
424        return []
425
426    def _signatures(self):
427        return ([(
[14136]428            'Mrs. Uniamikogbo, S.O., mnim, manupa <br /> Prin. Asst Registrar  <br /> '
[11555]429            'Exams, Records and Data Processing Division <br /> For: Registrar')],)
[10922]430
[13834]431    def render(self):
432        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]433        Term = translate(_('Sem.'), target_language=portal_language)
434        Code = translate(_('Code'), target_language=portal_language)
435        Title = translate(_('Title'), target_language=portal_language)
436        Cred = translate(_('Credits'), target_language=portal_language)
437        Score = translate(_('Score'), target_language=portal_language)
438        Grade = translate(_('Grade'), target_language=portal_language)
[13834]439        studentview = StudentBasePDFFormPage(self.context.student,
440            self.request, self.omit_fields)
441        students_utils = getUtility(IStudentsUtils)
442
443        tableheader = [(Code,'code', 2.5),
444                         (Title,'title', 7),
445                         (Term, 'semester', 1.5),
446                         (Cred, 'credits', 1.5),
[14136]447                         (Score, 'total_score', 1.5),
[13834]448                         (Grade, 'grade', 1.5),
449                         ]
450
451        return students_utils.renderPDFTranscript(
452            self, 'transcript.pdf',
453            self.context.student, studentview,
454            omit_fields=self.omit_fields,
455            tableheader=tableheader,
456            signatures=self._signatures(),
457            sigs_in_footer=self._sigsInFooter(),
458            )
459
[13059]460class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
[10922]461    """Deliver a PDF Admission slip.
462    """
463
464    @property
465    def label(self):
466        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]467        return translate(_('e-Admission Slip \n'),
468            target_language=portal_language) \
[10922]469            + ' %s' % self.context.display_fullname
[11597]470
[13059]471class CustomExportPDFClearanceSlip(NigeriaExportPDFClearanceSlip):
[11606]472    """Deliver a PDF slip of the context.
473    """
474
475    @property
476    def label(self):
477        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[14114]478        return translate(_('Verification/Clearance Slip\n'),
[13866]479            target_language=portal_language) \
[11606]480            + ' %s' % self.context.display_fullname
481
[14084]482    @property
483    def form_fields(self):
484        if self.context.is_postgrad:
485            form_fields = grok.AutoFields(
486                ICustomPGStudentClearance).omit('clearance_locked')
487        else:
488            form_fields = grok.AutoFields(
489                ICustomUGStudentClearance).omit('clearance_locked')
490        if not getattr(self.context, 'officer_comment'):
491            form_fields = form_fields.omit('officer_comment')
[14104]492        form_fields = form_fields.omit('def_adm')
[14084]493        return form_fields
494
[11597]495class StudentGetMatricNumberPage(UtilityView, grok.View):
496    """ Construct and set the matriculation number.
497    """
498    grok.context(IStudent)
499    grok.name('get_matric_number')
500    grok.require('waeup.viewStudent')
501
502    def update(self):
503        students_utils = getUtility(IStudentsUtils)
504        msg, mnumber = students_utils.setMatricNumber(self.context)
505        if msg:
506            self.flash(msg, type="danger")
507        else:
508            self.flash(_('Matriculation number %s assigned.' % mnumber))
[11602]509            self.context.writeLogMessage(self, '%s assigned' % mnumber)
[11597]510        self.redirect(self.url(self.context))
511        return
512
513    def render(self):
[11607]514        return
515
[13059]516class ExportPDFMatricNumberSlip(UtilityView, grok.View):
[11607]517    """Deliver a PDF notification slip.
518    """
519    grok.context(ICustomStudent)
520    grok.name('matric_number_slip.pdf')
521    grok.require('waeup.viewStudent')
522    prefix = 'form'
523
524    form_fields = grok.AutoFields(ICustomStudent).select(
525        'student_id', 'matric_number')
[13713]526    omit_fields = ('date_of_birth', 'current_level', 'flash_notice')
[11607]527
528    @property
[13489]529    def title(self):
530        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]531        return translate(_('Matriculation Number'), 'waeup.kofa',
[13489]532            target_language=portal_language)
533
534    @property
[11607]535    def label(self):
536        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]537        return translate(_('Matriculation Number Slip\n'),
538            target_language=portal_language) \
[11607]539            + ' %s' % self.context.display_fullname
540
541    def render(self):
542        if self.context.state not in (PAID,) or not self.context.is_fresh \
543            or not self.context.matric_number:
544            self.flash('Not allowed.', type="danger")
545            self.redirect(self.url(self.context))
546            return
547        students_utils = getUtility(IStudentsUtils)
[11609]548        pre_text = _('Congratulations! Your acceptance fee and school fees ' +
549                     'payments have been received and your matriculation ' +
550                     'number generated with details as follows.')
[11607]551        return students_utils.renderPDFAdmissionLetter(self,
552            self.context.student, omit_fields=self.omit_fields,
[13353]553            pre_text=pre_text, post_text='')
554
[13489]555class ExportPersonalDataSlip(UtilityView, grok.View):
556    """Deliver a PDF notification slip.
557    """
558    grok.context(ICustomStudent)
559    grok.name('personal_data_slip.pdf')
560    grok.require('waeup.viewStudent')
561    prefix = 'form'
562    note = None
563
564    form_fields = grok.AutoFields(ICustomStudentPersonal).omit('personal_updated')
[13713]565    omit_fields = ('suspended', 'suspended_comment', 'adm_code',
566                   'certificate', 'flash_notice')
[13489]567
568    @property
569    def title(self):
570        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]571        return translate(_('Personal Data'), 'waeup.kofa',
[13489]572            target_language=portal_language)
573
574    @property
575    def label(self):
576        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
[13866]577        return translate(_('Personal Data Slip\n'),
578            target_language=portal_language) \
[13489]579            + ' %s' % self.context.display_fullname
580
581    def render(self):
582        studentview = StudentBasePDFFormPage(self.context.student,
583            self.request, self.omit_fields)
584        students_utils = getUtility(IStudentsUtils)
585        return students_utils.renderPDF(self, 'personal_data_slip.pdf',
586            self.context.student, studentview, note=self.note,
587            omit_fields=self.omit_fields)
588
[13462]589class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
590    """ Page to manage bed tickets.
591    This manage form page is for both students and students officers.
592    """
593    with_hostel_selection = True
594
[13353]595class CustomBedTicketAddPage(BedTicketAddPage):
[13360]596    with_ac = False
[13380]597
598class CustomStudentFilesUploadPage(StudentFilesUploadPage):
599    """ View to upload files by student. Inherit from same class in
600    base package, not from kofacustom.nigeria which
601    requires that no application slip exists.
[13770]602    """
603
604class CustomCourseTicketDisplayFormPage(CourseTicketDisplayFormPage):
605    """ Page to display course tickets
606    """
607    form_fields = grok.AutoFields(ICustomCourseTicket)
608
609class CustomCourseTicketManageFormPage(CourseTicketManageFormPage):
610    """ Page to manage course tickets
611    """
612    form_fields = grok.AutoFields(ICustomCourseTicket)
613    form_fields['title'].for_display = True
614    form_fields['fcode'].for_display = True
615    form_fields['dcode'].for_display = True
616    form_fields['semester'].for_display = True
617    form_fields['passmark'].for_display = True
618    form_fields['credits'].for_display = True
619    form_fields['mandatory'].for_display = False
620    form_fields['automatic'].for_display = True
621    form_fields['carry_over'].for_display = True
622
623class CustomEditScoresPage(EditScoresPage):
624    """Page that filters and lists students.
625    """
626    grok.template('editscorespage')
627
[13937]628
629    def _extract_uploadfile(self, uploadfile):
630        """Get a mapping of student-ids to scores.
631
632        The mapping is constructed by reading contents from `uploadfile`.
633
634        We expect uploadfile to be a regular CSV file with columns
635        ``student_id``, ``score`` and ``ca`` (other cols are ignored).
636        """
637        result = dict()
638        data = StringIO(uploadfile.read())  # ensure we have something seekable
639        reader = csv.DictReader(data)
640        for row in reader:
641            if not ('student_id' in row and 'score' in row and 'ca' in row):
642                continue
643            result[row['student_id']] = (row['score'], row['ca'])
644        return result
645
[13770]646    def update(self,  *args, **kw):
647        form = self.request.form
[13937]648        ob_class = self.__implemented__.__name__.replace('waeup.kofa.', '')
[13770]649        self.current_academic_session = grok.getSite()[
650            'configuration'].current_academic_session
651        if self.context.__parent__.__parent__.score_editing_disabled:
652            self.flash(_('Score editing disabled.'), type="warning")
653            self.redirect(self.url(self.context))
654            return
655        if not self.current_academic_session:
656            self.flash(_('Current academic session not set.'), type="warning")
657            self.redirect(self.url(self.context))
658            return
[13939]659        self.session_title = academic_sessions_vocab.getTerm(
660            self.current_academic_session).title
[13770]661        self.tickets = self._searchCatalog(self.current_academic_session)
[14149]662        self.editable_tickets = [
[13770]663            ticket for ticket in self.tickets if ticket.editable_by_lecturer]
664        if not self.tickets:
665            self.flash(_('No student found.'), type="warning")
666            self.redirect(self.url(self.context))
667            return
[13937]668        if not 'UPDATE_TABLE' in form and not 'UPDATE_FILE' in form:
669            return
670
[14149]671        if not self.editable_tickets:
[13937]672            return
673        if 'UPDATE_FILE' in form:
674            if form['uploadfile']:
675                try:
676                    formvals = self._extract_uploadfile(form['uploadfile'])
677                except:
678                    self.flash(
679                        _('Uploaded file contains illegal data. Ignored'),
680                        type="danger")
681                    return
682            else:
683                self.flash(
684                    _('No file provided.'), type="danger")
[13770]685                return
[13937]686        else:
687            formvals = dict(zip(form['sids'], zip(form['scores'], form['cas'])))
688        error = ''
[14149]689        # In AAUE only editable tickets are shown, see also customized
690        # pagetemplate
691        for ticket in self.editable_tickets:
[13937]692            ticket_error = False
693            score = ticket.score
694            ca = ticket.ca
695            sid = ticket.student.student_id
696            if formvals[sid][0] == '':
697                score = None
698            if formvals[sid][1] == '':
699                ca = None
700            try:
701                if formvals[sid][0]:
702                    score = int(formvals[sid][0])
703                if formvals[sid][1]:
704                    ca = int(formvals[sid][1])
705            except ValueError:
706                error += '%s, ' % ticket.student.display_fullname
707                ticket_error = True
708            if not ticket_error and ticket.score != score:
[14113]709                try:
710                    ticket.score = score
711                except TooBig:
712                    error += '%s, ' % ticket.student.display_fullname
713                    ticket_error = True
714                    pass
[13937]715                ticket.student.__parent__.logger.info(
716                    '%s - %s %s/%s score updated (%s)' %
717                    (ob_class, ticket.student.student_id,
718                     ticket.level, ticket.code, score))
719            if not ticket_error and ticket.ca != ca:
[14113]720                try:
721                    ticket.ca = ca
722                except TooBig:
723                    error += '%s, ' % ticket.student.display_fullname
724                    pass
[13937]725                ticket.student.__parent__.logger.info(
726                    '%s - %s %s/%s ca updated (%s)' %
727                    (ob_class, ticket.student.student_id,
728                     ticket.level, ticket.code, ca))
729        if error:
730            self.flash(_('Error: Score(s) and CA(s) of %s have not be updated. '
[14113]731              % error.strip(', ')), type="danger")
[13939]732            return
733        self.flash(_('You successfully updated course results.'))
[13900]734        return
735
736class CustomExportPDFScoresSlip(ExportPDFScoresSlip):
737    """Deliver a PDF slip of course tickets for a lecturer.
738    """
739
740    def table_data(self, session):
741        cat = queryUtility(ICatalog, name='coursetickets_catalog')
742        coursetickets = cat.searchResults(
743            session=(session, session),
744            code=(self.context.code, self.context.code)
745            )
[14149]746        # In AAUE only editable tickets can be printed
747        editable_tickets = [
748            ticket for ticket in coursetickets if ticket.editable_by_lecturer]
[13963]749        header = [[_(''),
750                   _('Matric No.'),
[13900]751                   _('Reg. No.'),
752                   _('Fullname'),
753                   _('Status'),
[13963]754                   _('Course of\nStudies'),
[13900]755                   _('Level'),
[13963]756                   _('Exam\nScore'),
[13964]757                   _(' CA  '),
758                   _('Total '),
[13963]759                   _('Grade'),
760                   ],]
[13907]761        tickets = []
[13963]762        no = 1
[14149]763        # In AAUE only editable tickets can be printed
764        for ticket in editable_tickets:
[13963]765            if None in (ticket.score, ticket.ca):
766                total = 'n/a'
[13964]767                grade = 'n/a'
[13963]768            else:
769                total = ticket.score + ticket.ca
[13964]770                grade = getGradeWeightFromScore(total)[0]
771            fullname = textwrap.fill(ticket.student.display_fullname, 30)
[13963]772            row = [no,
773                  ticket.student.matric_number,
[13900]774                  ticket.student.reg_number,
[13964]775                  fullname,
[13900]776                  ticket.student.translated_state,
777                  ticket.student.certcode,
778                  ticket.level,
[13963]779                  ticket.ca,
[13900]780                  ticket.score,
[13963]781                  total,
[13964]782                  grade,
[13963]783                  ]
[13907]784            tickets.append(row)
[13963]785            no += 1
[13997]786        return header + sorted(tickets,
[14068]787            key=lambda value: value[5] + value[3] + str(value[6]))
Note: See TracBrowser for help on using the repository browser.