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

Last change on this file since 13770 was 13770, checked in by Henrik Bettermann, 9 years ago

Customize ICourseTicket. Add field 'ca'.

Customize EditScoresPage?, CourseTicketManageFormPage?, CourseTicketDisplayFormPage? and editscorespage.pt accordingly.

  • Property svn:keywords set to Id
File size: 21.9 KB
Line 
1## $Id: browser.py 13770 2016-03-08 17:21:35Z 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
19from zope.i18n import translate
20from zope.component import getUtility
21from zope.security import checkPermission
22from zope.formlib.textwidgets import BytesDisplayWidget
23from waeup.kofa.browser.layout import UtilityView
24from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
25from waeup.kofa.interfaces import IKofaUtils
26from waeup.kofa.students.interfaces import IStudentsUtils, IStudent
27from waeup.kofa.students.workflow import PAID, REGISTERED
28from waeup.kofa.students.browser import (
29    StartClearancePage,
30    StudentBasePDFFormPage,
31    CourseTicketAddFormPage,
32    StudyLevelDisplayFormPage,
33    ExportPDFTranscriptSlip,
34    ExportPDFAdmissionSlip,
35    BedTicketAddPage,
36    StudentFilesUploadPage,
37    PaymentsManageFormPage,
38    CourseTicketDisplayFormPage,
39    CourseTicketManageFormPage,
40    EditScoresPage
41    )
42from kofacustom.nigeria.students.browser import (
43    NigeriaOnlinePaymentDisplayFormPage,
44    NigeriaOnlinePaymentAddFormPage,
45    NigeriaExportPDFPaymentSlip,
46    NigeriaExportPDFCourseRegistrationSlip,
47    NigeriaExportPDFClearanceSlip,
48    NigeriaStudentPersonalDisplayFormPage,
49    NigeriaStudentPersonalEditFormPage,
50    NigeriaStudentPersonalManageFormPage,
51    NigeriaStudentClearanceEditFormPage,
52    NigeriaAccommodationManageFormPage,
53    )
54from waeup.aaue.students.interfaces import (
55    ICustomStudentOnlinePayment,
56    ICustomStudentStudyLevel,
57    ICustomStudent,
58    ICustomStudentPersonal,
59    ICustomStudentPersonalEdit,
60    ICustomUGStudentClearance,
61    ICustomCourseTicket)
62from waeup.aaue.interswitch.browser import gateway_net_amt
63from waeup.aaue.interfaces import MessageFactory as _
64
65class CustomStudentPersonalDisplayFormPage(NigeriaStudentPersonalDisplayFormPage):
66    """ Page to display student personal data
67    """
68    form_fields = grok.AutoFields(ICustomStudentPersonal)
69    form_fields['perm_address'].custom_widget = BytesDisplayWidget
70    form_fields['father_address'].custom_widget = BytesDisplayWidget
71    form_fields['mother_address'].custom_widget = BytesDisplayWidget
72    form_fields['next_kin_address'].custom_widget = BytesDisplayWidget
73    form_fields[
74        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
75
76class CustomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage):
77    """ Page to edit personal data
78    """
79    form_fields = grok.AutoFields(ICustomStudentPersonalEdit).omit('personal_updated')
80
81class CustomStudentPersonalManageFormPage(NigeriaStudentPersonalManageFormPage):
82    """ Page to edit personal data
83    """
84    form_fields = grok.AutoFields(ICustomStudentPersonal)
85    form_fields['personal_updated'].for_display = True
86    form_fields[
87        'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le')
88
89class CustomStudentClearanceEditFormPage(NigeriaStudentClearanceEditFormPage):
90    """ View to edit student clearance data by student
91    """
92
93    @property
94    def form_fields(self):
95        if self.context.is_postgrad:
96            form_fields = grok.AutoFields(ICustomPGStudentClearance).omit(
97            'clearance_locked', 'nysc_location', 'clr_code', 'officer_comment',
98            'physical_clearance_date')
99        else:
100            form_fields = grok.AutoFields(ICustomUGStudentClearance).omit(
101            'clearance_locked', 'clr_code', 'officer_comment',
102            'physical_clearance_date')
103        return form_fields
104
105class CustomStartClearancePage(StartClearancePage):
106    with_ac = False
107
108    @property
109    def all_required_fields_filled(self):
110        if not self.context.email:
111            return _("Email address is missing."), 'edit_base'
112        if not self.context.phone:
113            return _("Phone number is missing."), 'edit_base'
114        if not self.context.father_name:
115            return _("Personal data form is not properly filled."), 'edit_personal'
116        return
117
118class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage):
119    """ Page to view an online payment ticket
120    """
121    grok.context(ICustomStudentOnlinePayment)
122    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
123        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
124    form_fields[
125        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
126    form_fields[
127        'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
128
129class CustomOnlinePaymentAddFormPage(NigeriaOnlinePaymentAddFormPage):
130    """ Page to add an online payment ticket
131    """
132    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).select(
133        'p_category')
134
135class CustomPaymentsManageFormPage(PaymentsManageFormPage):
136    """ Page to manage the student payments.
137
138    This manage form page is for both students and students officers.
139    """
140    @property
141    def manage_payments_allowed(self):
142        return checkPermission('waeup.manageStudent', self.context)
143
144class CustomExportPDFPaymentSlip(NigeriaExportPDFPaymentSlip):
145    """Deliver a PDF slip of the context.
146    """
147    grok.context(ICustomStudentOnlinePayment)
148    form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit(
149        'provider_amt', 'gateway_amt', 'thirdparty_amt', 'p_item')
150    form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
151    form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
152
153    @property
154    def note(self):
155        p_session = self.context.p_session
156        try:
157            academic_session = grok.getSite()['configuration'][str(p_session)]
158        except KeyError:
159            academic_session = None
160        text =  '\n\n The Amount Authorized is inclusive of: '
161        if self.context.p_category in ('schoolfee_incl', 'schoolfee_1') \
162            and academic_session:
163            welfare_fee = gateway_net_amt(academic_session.welfare_fee)
164            union_fee = gateway_net_amt(academic_session.union_fee)
165            text += ('School Fee, '
166                     '%s Naira Student Union Dues, '
167                     '%s Naira Student Welfare Assurance Fee and '
168                     % (union_fee, welfare_fee))
169        elif self.context.p_category in (
170            'clearance_incl', 'clearance_medical_incl') and academic_session:
171            matric_gown_fee = gateway_net_amt(academic_session.matric_gown_fee)
172            lapel_fee = gateway_net_amt(academic_session.lapel_fee)
173            text += ('Acceptance Fee, '
174                     '%s Naira Matriculation Gown Fee, '
175                     '%s Naira Lapel/File Fee and '
176                     % (matric_gown_fee, lapel_fee))
177        return text + '250.0 Naira Transaction Charge.'
178
179class CustomStudyLevelDisplayFormPage(StudyLevelDisplayFormPage):
180    """ Page to display student study levels
181    """
182    grok.context(ICustomStudentStudyLevel)
183    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
184        'total_credits', 'gpa', 'level')
185    form_fields[
186        'validation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
187
188class CustomExportPDFCourseRegistrationSlip(
189    NigeriaExportPDFCourseRegistrationSlip):
190    """Deliver a PDF slip of the context.
191    """
192    grok.context(ICustomStudentStudyLevel)
193    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit(
194        'level_session', 'level_verdict',
195        'validated_by', 'validation_date', 'gpa', 'level')
196
197    omit_fields = ('password', 'suspended', 'suspended_comment',
198        'phone', 'adm_code', 'sex', 'email', 'date_of_birth',
199        'department', 'current_mode', 'current_level', 'flash_notice')
200
201    def update(self):
202        if self.context.student.state != REGISTERED \
203            and self.context.student.current_level == self.context.level:
204            self.flash(_('Forbidden'), type="warning")
205            self.redirect(self.url(self.context))
206
207    @property
208    def label(self):
209        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
210        lang = self.request.cookies.get('kofa.language', portal_language)
211        level_title = translate(self.context.level_title, 'waeup.kofa',
212            target_language=lang)
213        line0 = ''
214        if self.context.student.current_mode.endswith('_pt'):
215            line0 = 'DIRECTORATE OF PART-TIME DEGREE PROGRAMMES\n'
216        line1 = translate(_('Course Registration Slip'),
217            'waeup.kofa', target_language=portal_language) \
218            + ' %s' % level_title
219        line2 = translate(_('Session'),
220            'waeup.kofa', target_language=portal_language) \
221            + ' %s' % self.context.getSessionString
222        return '%s%s\n%s' % (line0, line1, line2)
223
224    @property
225    def title(self):
226        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
227        return translate(_('Units Registered'), 'waeup.kofa',
228            target_language=portal_language)
229
230    def _signatures(self):
231        if self.context.student.current_mode.endswith('_pt') \
232            or self.context.student.current_mode == 'found':
233            return (
234                [('I have selected the course on the advise of my Head of '
235                 'Department. <br>', _('Student\'s Signature'), '<br>')],
236                [('This student has satisfied the department\'s requirements. '
237                 'I recommend to approve the course registration. <br>',
238                 _('Head of Department\'s Signature'), '<br>')],
239                [('' , _('Principal Assistant Registrar\'s Signature'), '<br>')],
240                [('', _('Director\'s Signature'))]
241                )
242        if self.context.student.current_mode in (
243            'de_ft', 'ug_ft', 'dp_ft', 'transfer'):
244            return ([_('Academic Adviser\'s Signature'),
245                _('Faculty Officer\'s Signature'),
246                _('Student\'s Signature')],)
247
248        if self.context.student.current_mode in ('special_pg_ft', 'special_pg_pt'):
249            return (
250                [('I declare that all items of information supplied above are correct:' ,
251                    _('Student\'s Signature'), '<br>')],
252                [('We approved the above registration:',
253                    _('Major Supervisor (Name / Signature)'), '')],
254                [('', _('Co-Supervisor (Name / Signature)'), '')],
255                [('', _('Head of Department'), '<br>')],
256                [('The student has satisfied the conditions for renewal of '
257                  'registration for graduate school programme in this university:',
258                  _('Secretary <br /> (School of Postgraduate Studies)'), '')],
259                [('', _('Dean <br /> (School of Postgraduate Studies)'), '')],
260                )
261        return None
262
263
264    def render(self):
265        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
266        Sem = translate('Sem.', 'waeup.kofa', target_language=portal_language)
267        Code = translate('Code', 'waeup.kofa', target_language=portal_language)
268        Title = translate('Title', 'waeup.kofa', target_language=portal_language)
269        Cred = translate('Cred.', 'waeup.kofa', target_language=portal_language)
270        Score = translate('Score', 'waeup.kofa', target_language=portal_language)
271        Grade = translate('Grade', 'waeup.kofa', target_language=portal_language)
272        Signature = translate(_('Lecturer\'s Signature'), 'waeup.aaue',
273            target_language=portal_language)
274        studentview = StudentBasePDFFormPage(self.context.student,
275            self.request, self.omit_fields)
276        students_utils = getUtility(IStudentsUtils)
277
278        tabledata = []
279        tableheader = []
280        contenttitle = []
281        for i in range(1,7):
282            tabledata.append(sorted(
283                [value for value in self.context.values() if value.semester == i],
284                key=lambda value: str(value.semester) + value.code))
285            tableheader.append([(Code,'code', 2.0),
286                               (Title,'title', 7),
287                               (Cred, 'credits', 1.5),
288                               (Score, 'score', 1.4),
289                               (Grade, 'grade', 1.4),
290                               (Signature, 'dummy', 3),
291                               ])
292        if len(self.label.split('\n')) == 3:
293            topMargin = 1.9
294        elif len(self.label.split('\n')) == 2:
295            topMargin = 1.7
296        else:
297            topMargin = 1.5
298        return students_utils.renderPDF(
299            self, 'course_registration_slip.pdf',
300            self.context.student, studentview,
301            tableheader=tableheader,
302            tabledata=tabledata,
303            signatures=self._signatures(),
304            topMargin=topMargin,
305            omit_fields=self.omit_fields
306            )
307
308class CustomExportPDFTranscriptSlip(ExportPDFTranscriptSlip):
309    """Deliver a PDF slip of the context.
310    """
311
312    def _sigsInFooter(self):
313        return []
314
315    def _signatures(self):
316        return ([(
317            'Akhimien Felicia O. (MANUPA) <br /> Principal Assistant Registrar  <br /> '
318            'Exams, Records and Data Processing Division <br /> For: Registrar')],)
319
320class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
321    """Deliver a PDF Admission slip.
322    """
323
324    @property
325    def label(self):
326        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
327        return translate(_('e-Admission Slip \n'),
328            'waeup.kofa', target_language=portal_language) \
329            + ' %s' % self.context.display_fullname
330
331class CustomExportPDFClearanceSlip(NigeriaExportPDFClearanceSlip):
332    """Deliver a PDF slip of the context.
333    """
334
335    @property
336    def label(self):
337        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
338        return translate(_('Clearance Slip\n'),
339            'waeup.kofa', target_language=portal_language) \
340            + ' %s' % self.context.display_fullname
341
342class StudentGetMatricNumberPage(UtilityView, grok.View):
343    """ Construct and set the matriculation number.
344    """
345    grok.context(IStudent)
346    grok.name('get_matric_number')
347    grok.require('waeup.viewStudent')
348
349    def update(self):
350        students_utils = getUtility(IStudentsUtils)
351        msg, mnumber = students_utils.setMatricNumber(self.context)
352        if msg:
353            self.flash(msg, type="danger")
354        else:
355            self.flash(_('Matriculation number %s assigned.' % mnumber))
356            self.context.writeLogMessage(self, '%s assigned' % mnumber)
357        self.redirect(self.url(self.context))
358        return
359
360    def render(self):
361        return
362
363class ExportPDFMatricNumberSlip(UtilityView, grok.View):
364    """Deliver a PDF notification slip.
365    """
366    grok.context(ICustomStudent)
367    grok.name('matric_number_slip.pdf')
368    grok.require('waeup.viewStudent')
369    prefix = 'form'
370
371    form_fields = grok.AutoFields(ICustomStudent).select(
372        'student_id', 'matric_number')
373    omit_fields = ('date_of_birth', 'current_level', 'flash_notice')
374
375    @property
376    def title(self):
377        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
378        return translate(_('Matriculation Number'), 'waeup.kofa',
379            target_language=portal_language)
380
381    @property
382    def label(self):
383        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
384        return translate(_('Matriculation Number Slip\n'),
385            'waeup.kofa', target_language=portal_language) \
386            + ' %s' % self.context.display_fullname
387
388    def render(self):
389        if self.context.state not in (PAID,) or not self.context.is_fresh \
390            or not self.context.matric_number:
391            self.flash('Not allowed.', type="danger")
392            self.redirect(self.url(self.context))
393            return
394        students_utils = getUtility(IStudentsUtils)
395        pre_text = _('Congratulations! Your acceptance fee and school fees ' +
396                     'payments have been received and your matriculation ' +
397                     'number generated with details as follows.')
398        return students_utils.renderPDFAdmissionLetter(self,
399            self.context.student, omit_fields=self.omit_fields,
400            pre_text=pre_text, post_text='')
401
402class ExportPersonalDataSlip(UtilityView, grok.View):
403    """Deliver a PDF notification slip.
404    """
405    grok.context(ICustomStudent)
406    grok.name('personal_data_slip.pdf')
407    grok.require('waeup.viewStudent')
408    prefix = 'form'
409    note = None
410
411    form_fields = grok.AutoFields(ICustomStudentPersonal).omit('personal_updated')
412    omit_fields = ('suspended', 'suspended_comment', 'adm_code',
413                   'certificate', 'flash_notice')
414
415    @property
416    def title(self):
417        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
418        return translate(_('Personal Data'), 'waeup.kofa',
419            target_language=portal_language)
420
421    @property
422    def label(self):
423        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
424        return translate(_('Personal Data Slip\n'),
425            'waeup.kofa', target_language=portal_language) \
426            + ' %s' % self.context.display_fullname
427
428    def render(self):
429        studentview = StudentBasePDFFormPage(self.context.student,
430            self.request, self.omit_fields)
431        students_utils = getUtility(IStudentsUtils)
432        return students_utils.renderPDF(self, 'personal_data_slip.pdf',
433            self.context.student, studentview, note=self.note,
434            omit_fields=self.omit_fields)
435
436class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage):
437    """ Page to manage bed tickets.
438    This manage form page is for both students and students officers.
439    """
440    with_hostel_selection = True
441
442class CustomBedTicketAddPage(BedTicketAddPage):
443    with_ac = False
444
445class CustomStudentFilesUploadPage(StudentFilesUploadPage):
446    """ View to upload files by student. Inherit from same class in
447    base package, not from kofacustom.nigeria which
448    requires that no application slip exists.
449    """
450
451class CustomCourseTicketDisplayFormPage(CourseTicketDisplayFormPage):
452    """ Page to display course tickets
453    """
454    form_fields = grok.AutoFields(ICustomCourseTicket)
455
456class CustomCourseTicketManageFormPage(CourseTicketManageFormPage):
457    """ Page to manage course tickets
458    """
459    form_fields = grok.AutoFields(ICustomCourseTicket)
460    form_fields['title'].for_display = True
461    form_fields['fcode'].for_display = True
462    form_fields['dcode'].for_display = True
463    form_fields['semester'].for_display = True
464    form_fields['passmark'].for_display = True
465    form_fields['credits'].for_display = True
466    form_fields['mandatory'].for_display = False
467    form_fields['automatic'].for_display = True
468    form_fields['carry_over'].for_display = True
469
470class CustomEditScoresPage(EditScoresPage):
471    """Page that filters and lists students.
472    """
473    grok.template('editscorespage')
474
475    def update(self,  *args, **kw):
476        form = self.request.form
477        ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
478        self.current_academic_session = grok.getSite()[
479            'configuration'].current_academic_session
480        if self.context.__parent__.__parent__.score_editing_disabled:
481            self.flash(_('Score editing disabled.'), type="warning")
482            self.redirect(self.url(self.context))
483            return
484        if not self.current_academic_session:
485            self.flash(_('Current academic session not set.'), type="warning")
486            self.redirect(self.url(self.context))
487            return
488        self.tickets = self._searchCatalog(self.current_academic_session)
489        editable_tickets = [
490            ticket for ticket in self.tickets if ticket.editable_by_lecturer]
491        if not self.tickets:
492            self.flash(_('No student found.'), type="warning")
493            self.redirect(self.url(self.context))
494            return
495        if 'UPDATE' in form:
496            tno = 0
497            error = ''
498            if not editable_tickets:
499                return
500            scores = form['scores']
501            cas = form['cas']
502            if isinstance(scores, basestring):
503                scores = [scores]
504            if isinstance(cas, basestring):
505                cas = [cas]
506            for ticket in editable_tickets:
507                ticket_error = False
508                score = ticket.score
509                ca = ticket.ca
510                if scores[tno] == '':
511                    score = None
512                if cas[tno] == '':
513                    ca = None
514                try:
515                    if scores[tno]:
516                        score = int(scores[tno])
517                    if cas[tno]:
518                        ca = int(cas[tno])
519                except ValueError:
520                    error += '%s, ' % ticket.student.display_fullname
521                    ticket_error = True
522                if not ticket_error and ticket.score != score:
523                    ticket.score = score
524                    ticket.student.__parent__.logger.info(
525                        '%s - %s %s/%s score updated (%s)' %
526                        (ob_class, ticket.student.student_id,
527                         ticket.level, ticket.code, score))
528                if not ticket_error and ticket.ca != ca:
529                    ticket.ca = ca
530                    ticket.student.__parent__.logger.info(
531                        '%s - %s %s/%s ca updated (%s)' %
532                        (ob_class, ticket.student.student_id,
533                         ticket.level, ticket.code, ca))
534                tno += 1
535            if error:
536                self.flash(_('Error: Score(s) and CA(s) of %s have not be updated. '
537                  'Only integers are allowed.' % error.strip(', ')),
538                  type="danger")
539        return
Note: See TracBrowser for help on using the repository browser.