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

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

Change signature name.

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