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

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

Show course results only if students are returning or current level is different from course level.

  • Property svn:keywords set to Id
File size: 28.5 KB
Line 
1## $Id: browser.py 14000 2016-06-30 09:23:19Z 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, RETURNING
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
214    @property
215    def show_results(self):
216        isStudent = getattr(
217            self.request.principal, 'user_type', None) == 'student'
218        if isStudent and self.context.student.state != RETURNING \
219            and self.context.student.current_level == self.context.level:
220            return False
221        return True
222
223class CustomStudyLevelManageFormPage(StudyLevelManageFormPage):
224    """ Page to edit the student study level data
225    """
226    grok.context(ICustomStudentStudyLevel)
227
228class CustomStudyLevelEditFormPage(StudyLevelEditFormPage):
229    """ Page to edit the student study level data by students
230    """
231    grok.context(ICustomStudentStudyLevel)
232
233class CustomExportPDFCourseRegistrationSlip(
234    NigeriaExportPDFCourseRegistrationSlip):
235    """Deliver a PDF slip of the context.
236    """
237    grok.context(ICustomStudentStudyLevel)
238    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
239        'level_session', 'level_verdict',
240        'validated_by', 'validation_date', 'gpa', 'level')
241
242    omit_fields = ('password', 'suspended', 'suspended_comment',
243        'phone', 'adm_code', 'sex', 'email', 'date_of_birth',
244        'department', 'current_mode', 'current_level', 'flash_notice')
245
246    @property
247    def show_results(self):
248        isStudent = getattr(
249            self.request.principal, 'user_type', None) == 'student'
250        return not isStudent \
251            or self.context.student.current_level != self.context.level \
252            or self.context.student.state == RETURNING
253
254    def update(self):
255        if self.context.student.state != REGISTERED \
256            and self.context.student.current_level == self.context.level:
257            self.flash(_('Forbidden'), type="warning")
258            self.redirect(self.url(self.context))
259            return
260
261    @property
262    def label(self):
263        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
264        lang = self.request.cookies.get('kofa.language', portal_language)
265        level_title = translate(self.context.level_title, 'waeup.kofa',
266            target_language=lang)
267        line0 = ''
268        if self.context.student.is_postgrad:
269            line0 = 'SCHOOL OF POSTGRADUATE STUDIES\n'
270        elif self.context.student.current_mode.endswith('_pt'):
271            line0 = 'DIRECTORATE OF PART-TIME DEGREE PROGRAMMES\n'
272        line1 = translate(_('Course Registration Slip'),
273            target_language=portal_language) \
274            + ' %s' % level_title
275        line2 = translate(_('Session'),
276            target_language=portal_language) \
277            + ' %s' % self.context.getSessionString
278        return '%s%s\n%s' % (line0, line1, line2)
279
280    @property
281    def title(self):
282        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
283        return translate(_('Units Registered'), target_language=portal_language)
284
285    def _signatures(self):
286        if self.context.student.current_mode.endswith('_pt') \
287            or self.context.student.current_mode == 'found':
288            return (
289                [('I have selected the course on the advise of my Head of '
290                 'Department. <br>', _('Student\'s Signature'), '<br>')],
291                [('This student has satisfied the department\'s requirements. '
292                 'I recommend to approve the course registration. <br>',
293                 _('Head of Department\'s Signature'), '<br>')],
294                [('' , _('Deputy Registrar\'s Signature'), '<br>')],
295                [('', _('Director\'s Signature'))]
296                )
297        if self.context.student.current_mode in (
298            'de_ft', 'ug_ft', 'dp_ft', 'transfer'):
299            return ([_('Academic Adviser\'s Signature'),
300                _('Faculty Officer\'s Signature'),
301                _('Student\'s Signature')],)
302
303        if self.context.student.current_mode in ('special_pg_ft', 'special_pg_pt'):
304            return (
305                [('I declare that all items of information supplied above are correct:' ,
306                    _('Student\'s Signature'), '<br>')],
307                [('We approved the above registration:',
308                    _('Major Supervisor (Name / Signature)'), '')],
309                [('', _('Co-Supervisor (Name / Signature)'), '')],
310                [('', _('Head of Department'), '<br>')],
311                [('The student has satisfied the conditions for renewal of '
312                  'registration for graduate school programme in this university:',
313                  _('Secretary <br /> (School of Postgraduate Studies)'), '')],
314                [('', _('Dean <br /> (School of Postgraduate Studies)'), '')],
315                )
316        return None
317
318
319    def render(self):
320        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
321        Sem = translate(_('Sem.'), target_language=portal_language)
322        Code = translate(_('Code'), target_language=portal_language)
323        Title = translate(_('Title'), target_language=portal_language)
324        Cred = translate(_('Cred.'), target_language=portal_language)
325        if self.show_results:
326            Score = translate(_('Score'), target_language=portal_language)
327            #CA = translate(_('CA'), target_language=portal_language)
328            Grade = translate(_('Grade'), target_language=portal_language)
329        Signature = translate(_('Lecturer\'s Signature'), 'waeup.aaue',
330            target_language=portal_language)
331        studentview = StudentBasePDFFormPage(self.context.student,
332            self.request, self.omit_fields)
333        students_utils = getUtility(IStudentsUtils)
334
335        tabledata = []
336        tableheader = []
337        contenttitle = []
338        for i in range(1,7):
339            tabledata.append(sorted(
340                [value for value in self.context.values() if value.semester == i],
341                key=lambda value: str(value.semester) + value.code))
342            if self.show_results:
343                tableheader.append([(Code,'code', 2.0),
344                                   (Title,'title', 7),
345                                   (Cred, 'credits', 1.5),
346                                   (Score, 'score', 1.4),
347                                   #(CA, 'ca', 1.4),
348                                   (Grade, 'grade', 1.4),
349                                   (Signature, 'dummy', 3),
350                                   ])
351            else:
352                tableheader.append([(Code,'code', 2.0),
353                                   (Title,'title', 7),
354                                   (Cred, 'credits', 1.5),
355                                   (Signature, 'dummy', 3),
356                                   ])
357        if len(self.label.split('\n')) == 3:
358            topMargin = 1.9
359        elif len(self.label.split('\n')) == 2:
360            topMargin = 1.7
361        else:
362            topMargin = 1.5
363        return students_utils.renderPDF(
364            self, 'course_registration_slip.pdf',
365            self.context.student, studentview,
366            tableheader=tableheader,
367            tabledata=tabledata,
368            signatures=self._signatures(),
369            topMargin=topMargin,
370            omit_fields=self.omit_fields
371            )
372
373class CustomExportPDFTranscriptSlip(ExportPDFTranscriptSlip):
374    """Deliver a PDF slip of the context.
375    """
376
377    def _sigsInFooter(self):
378        return []
379
380    def _signatures(self):
381        return ([(
382            'Akhimien Felicia O. (MANUPA) <br /> Principal Assistant Registrar  <br /> '
383            'Exams, Records and Data Processing Division <br /> For: Registrar')],)
384
385    def render(self):
386        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
387        Term = translate(_('Sem.'), target_language=portal_language)
388        Code = translate(_('Code'), target_language=portal_language)
389        Title = translate(_('Title'), target_language=portal_language)
390        Cred = translate(_('Credits'), target_language=portal_language)
391        Score = translate(_('Score'), target_language=portal_language)
392        #CA = translate(_('CA'), target_language=portal_language)
393        Grade = translate(_('Grade'), target_language=portal_language)
394        studentview = StudentBasePDFFormPage(self.context.student,
395            self.request, self.omit_fields)
396        students_utils = getUtility(IStudentsUtils)
397
398        tableheader = [(Code,'code', 2.5),
399                         (Title,'title', 7),
400                         (Term, 'semester', 1.5),
401                         (Cred, 'credits', 1.5),
402                         (Score, 'score', 1.5),
403                         #(CA, 'ca', 1.5),
404                         (Grade, 'grade', 1.5),
405                         ]
406
407        return students_utils.renderPDFTranscript(
408            self, 'transcript.pdf',
409            self.context.student, studentview,
410            omit_fields=self.omit_fields,
411            tableheader=tableheader,
412            signatures=self._signatures(),
413            sigs_in_footer=self._sigsInFooter(),
414            )
415
416class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
417    """Deliver a PDF Admission slip.
418    """
419
420    @property
421    def label(self):
422        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
423        return translate(_('e-Admission Slip \n'),
424            target_language=portal_language) \
425            + ' %s' % self.context.display_fullname
426
427class CustomExportPDFClearanceSlip(NigeriaExportPDFClearanceSlip):
428    """Deliver a PDF slip of the context.
429    """
430
431    @property
432    def label(self):
433        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
434        return translate(_('Clearance Slip\n'),
435            target_language=portal_language) \
436            + ' %s' % self.context.display_fullname
437
438class StudentGetMatricNumberPage(UtilityView, grok.View):
439    """ Construct and set the matriculation number.
440    """
441    grok.context(IStudent)
442    grok.name('get_matric_number')
443    grok.require('waeup.viewStudent')
444
445    def update(self):
446        students_utils = getUtility(IStudentsUtils)
447        msg, mnumber = students_utils.setMatricNumber(self.context)
448        if msg:
449            self.flash(msg, type="danger")
450        else:
451            self.flash(_('Matriculation number %s assigned.' % mnumber))
452            self.context.writeLogMessage(self, '%s assigned' % mnumber)
453        self.redirect(self.url(self.context))
454        return
455
456    def render(self):
457        return
458
459class ExportPDFMatricNumberSlip(UtilityView, grok.View):
460    """Deliver a PDF notification slip.
461    """
462    grok.context(ICustomStudent)
463    grok.name('matric_number_slip.pdf')
464    grok.require('waeup.viewStudent')
465    prefix = 'form'
466
467    form_fields = grok.AutoFields(ICustomStudent).select(
468        'student_id', 'matric_number')
469    omit_fields = ('date_of_birth', 'current_level', 'flash_notice')
470
471    @property
472    def title(self):
473        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
474        return translate(_('Matriculation Number'), 'waeup.kofa',
475            target_language=portal_language)
476
477    @property
478    def label(self):
479        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
480        return translate(_('Matriculation Number Slip\n'),
481            target_language=portal_language) \
482            + ' %s' % self.context.display_fullname
483
484    def render(self):
485        if self.context.state not in (PAID,) or not self.context.is_fresh \
486            or not self.context.matric_number:
487            self.flash('Not allowed.', type="danger")
488            self.redirect(self.url(self.context))
489            return
490        students_utils = getUtility(IStudentsUtils)
491        pre_text = _('Congratulations! Your acceptance fee and school fees ' +
492                     'payments have been received and your matriculation ' +
493                     'number generated with details as follows.')
494        return students_utils.renderPDFAdmissionLetter(self,
495            self.context.student, omit_fields=self.omit_fields,
496            pre_text=pre_text, post_text='')
497
498class ExportPersonalDataSlip(UtilityView, grok.View):
499    """Deliver a PDF notification slip.
500    """
501    grok.context(ICustomStudent)
502    grok.name('personal_data_slip.pdf')
503    grok.require('waeup.viewStudent')
504    prefix = 'form'
505    note = None
506
507    form_fields = grok.AutoFields(ICustomStudentPersonal).omit('personal_updated')
508    omit_fields = ('suspended', 'suspended_comment', 'adm_code',
509                   'certificate', 'flash_notice')
510
511    @property
512    def title(self):
513        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
514        return translate(_('Personal Data'), 'waeup.kofa',
515            target_language=portal_language)
516
517    @property
518    def label(self):
519        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
520        return translate(_('Personal Data Slip\n'),
521            target_language=portal_language) \
522            + ' %s' % self.context.display_fullname
523
524    def render(self):
525        studentview = StudentBasePDFFormPage(self.context.student,
526            self.request, self.omit_fields)
527        students_utils = getUtility(IStudentsUtils)
528        return students_utils.renderPDF(self, 'personal_data_slip.pdf',
529            self.context.student, studentview, note=self.note,
530            omit_fields=self.omit_fields)
531
532class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
533    """ Page to manage bed tickets.
534    This manage form page is for both students and students officers.
535    """
536    with_hostel_selection = True
537
538class CustomBedTicketAddPage(BedTicketAddPage):
539    with_ac = False
540
541class CustomStudentFilesUploadPage(StudentFilesUploadPage):
542    """ View to upload files by student. Inherit from same class in
543    base package, not from kofacustom.nigeria which
544    requires that no application slip exists.
545    """
546
547class CustomCourseTicketDisplayFormPage(CourseTicketDisplayFormPage):
548    """ Page to display course tickets
549    """
550    form_fields = grok.AutoFields(ICustomCourseTicket)
551
552class CustomCourseTicketManageFormPage(CourseTicketManageFormPage):
553    """ Page to manage course tickets
554    """
555    form_fields = grok.AutoFields(ICustomCourseTicket)
556    form_fields['title'].for_display = True
557    form_fields['fcode'].for_display = True
558    form_fields['dcode'].for_display = True
559    form_fields['semester'].for_display = True
560    form_fields['passmark'].for_display = True
561    form_fields['credits'].for_display = True
562    form_fields['mandatory'].for_display = False
563    form_fields['automatic'].for_display = True
564    form_fields['carry_over'].for_display = True
565
566class CustomEditScoresPage(EditScoresPage):
567    """Page that filters and lists students.
568    """
569    grok.template('editscorespage')
570
571
572    def _extract_uploadfile(self, uploadfile):
573        """Get a mapping of student-ids to scores.
574
575        The mapping is constructed by reading contents from `uploadfile`.
576
577        We expect uploadfile to be a regular CSV file with columns
578        ``student_id``, ``score`` and ``ca`` (other cols are ignored).
579        """
580        result = dict()
581        data = StringIO(uploadfile.read())  # ensure we have something seekable
582        reader = csv.DictReader(data)
583        for row in reader:
584            if not ('student_id' in row and 'score' in row and 'ca' in row):
585                continue
586            result[row['student_id']] = (row['score'], row['ca'])
587        return result
588
589    def update(self,  *args, **kw):
590        form = self.request.form
591        ob_class = self.__implemented__.__name__.replace('waeup.kofa.', '')
592        self.current_academic_session = grok.getSite()[
593            'configuration'].current_academic_session
594        if self.context.__parent__.__parent__.score_editing_disabled:
595            self.flash(_('Score editing disabled.'), type="warning")
596            self.redirect(self.url(self.context))
597            return
598        if not self.current_academic_session:
599            self.flash(_('Current academic session not set.'), type="warning")
600            self.redirect(self.url(self.context))
601            return
602        self.session_title = academic_sessions_vocab.getTerm(
603            self.current_academic_session).title
604        self.tickets = self._searchCatalog(self.current_academic_session)
605        editable_tickets = [
606            ticket for ticket in self.tickets if ticket.editable_by_lecturer]
607        if not self.tickets:
608            self.flash(_('No student found.'), type="warning")
609            self.redirect(self.url(self.context))
610            return
611        if not 'UPDATE_TABLE' in form and not 'UPDATE_FILE' in form:
612            return
613
614        if not editable_tickets:
615            return
616        if 'UPDATE_FILE' in form:
617            if form['uploadfile']:
618                try:
619                    formvals = self._extract_uploadfile(form['uploadfile'])
620                except:
621                    self.flash(
622                        _('Uploaded file contains illegal data. Ignored'),
623                        type="danger")
624                    return
625            else:
626                self.flash(
627                    _('No file provided.'), type="danger")
628                return
629        else:
630            formvals = dict(zip(form['sids'], zip(form['scores'], form['cas'])))
631        error = ''
632        for ticket in editable_tickets:
633            ticket_error = False
634            score = ticket.score
635            ca = ticket.ca
636            sid = ticket.student.student_id
637            if formvals[sid][0] == '':
638                score = None
639            if formvals[sid][1] == '':
640                ca = None
641            try:
642                if formvals[sid][0]:
643                    score = int(formvals[sid][0])
644                if formvals[sid][1]:
645                    ca = int(formvals[sid][1])
646            except ValueError:
647                error += '%s, ' % ticket.student.display_fullname
648                ticket_error = True
649            if not ticket_error and ticket.score != score:
650                ticket.score = score
651                ticket.student.__parent__.logger.info(
652                    '%s - %s %s/%s score updated (%s)' %
653                    (ob_class, ticket.student.student_id,
654                     ticket.level, ticket.code, score))
655            if not ticket_error and ticket.ca != ca:
656                ticket.ca = ca
657                ticket.student.__parent__.logger.info(
658                    '%s - %s %s/%s ca updated (%s)' %
659                    (ob_class, ticket.student.student_id,
660                     ticket.level, ticket.code, ca))
661        if error:
662            self.flash(_('Error: Score(s) and CA(s) of %s have not be updated. '
663              'Only integers are allowed.' % error.strip(', ')),
664              type="danger")
665            return
666        self.flash(_('You successfully updated course results.'))
667        return
668
669class CustomExportPDFScoresSlip(ExportPDFScoresSlip):
670    """Deliver a PDF slip of course tickets for a lecturer.
671    """
672
673    def table_data(self, session):
674        cat = queryUtility(ICatalog, name='coursetickets_catalog')
675        coursetickets = cat.searchResults(
676            session=(session, session),
677            code=(self.context.code, self.context.code)
678            )
679        header = [[_(''),
680                   _('Matric No.'),
681                   _('Reg. No.'),
682                   _('Fullname'),
683                   _('Status'),
684                   _('Course of\nStudies'),
685                   _('Level'),
686                   _('Exam\nScore'),
687                   _(' CA  '),
688                   _('Total '),
689                   _('Grade'),
690                   ],]
691        tickets = []
692        no = 1
693        for ticket in list(coursetickets):
694            if None in (ticket.score, ticket.ca):
695                total = 'n/a'
696                grade = 'n/a'
697            else:
698                total = ticket.score + ticket.ca
699                grade = getGradeWeightFromScore(total)[0]
700            fullname = textwrap.fill(ticket.student.display_fullname, 30)
701            row = [no,
702                  ticket.student.matric_number,
703                  ticket.student.reg_number,
704                  fullname,
705                  ticket.student.translated_state,
706                  ticket.student.certcode,
707                  ticket.level,
708                  ticket.ca,
709                  ticket.score,
710                  total,
711                  grade,
712                  ]
713            tickets.append(row)
714            no += 1
715        return header + sorted(tickets,
716            key=lambda value: value[5] + str(value[6]) + value[3])
717
Note: See TracBrowser for help on using the repository browser.