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

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

Sort by certcode and fullname.

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