source: main/waeup.uniben/trunk/src/waeup/uniben/students/utils.py @ 17497

Last change on this file since 17497 was 17457, checked in by Henrik Bettermann, 17 months ago

Implement new school fee calculation based on civ configuration tables.

  • Property svn:keywords set to Id
File size: 31.3 KB
Line 
1## $Id: utils.py 17457 2023-06-26 21:30:00Z henrik $
2##
3## Copyright (C) 2011 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 os
20import csv
21from time import time
22from reportlab.platypus import Paragraph, Table
23from zope.component import createObject, getUtility
24from reportlab.lib.styles import getSampleStyleSheet
25from waeup.kofa.browser.pdf import ENTRY1_STYLE
26from waeup.kofa.interfaces import (IKofaUtils, ADMITTED, CLEARANCE,
27    CLEARED, REQUESTED, RETURNING, PAID, REGISTERED, VALIDATED, GRADUATED)
28from waeup.kofa.utils.helpers import to_timezone
29from waeup.kofa.students.utils import (
30    trans, render_student_data, formatted_text, render_transcript_data,
31    SLIP_STYLE)
32from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
33from waeup.uniben.interfaces import MessageFactory as _
34
35SCHOOLFEES = dict()
36
37schoolfees_path = os.path.join(
38    os.path.dirname(__file__), 'schoolfees_22.csv')
39reader = csv.DictReader(open(schoolfees_path, 'rb'))
40SCHOOLFEES[22] = {line['code']: {item[0]:item[1] for item in line.items()}
41    for line in reader}
42
43
44schoolfees_path = os.path.join(
45    os.path.dirname(__file__), 'schoolfees_20.csv')
46reader = csv.DictReader(open(schoolfees_path, 'rb'))
47SCHOOLFEES[20] = {line['code']: {item[0]:item[1] for item in line.items()}
48    for line in reader}
49
50
51schoolfees_path = os.path.join(
52    os.path.dirname(__file__), 'schoolfees_17.csv')
53reader = csv.DictReader(open(schoolfees_path, 'rb'))
54SCHOOLFEES[17] = {line['code']: {item[0]:item[1] for item in line.items()}
55    for line in reader}
56
57schoolfees_path = os.path.join(
58    os.path.dirname(__file__), 'schoolfees_12.csv')
59reader = csv.DictReader(open(schoolfees_path, 'rb'))
60SCHOOLFEES[12] = {line['code']: {item[0]:item[1] for item in line.items()}
61    for line in reader}
62
63class CustomStudentsUtils(NigeriaStudentsUtils):
64    """A collection of customized methods.
65
66    """
67
68    SEPARATORS_DICT = {
69        'form.fst_sit_fname': _(u'First Sitting Record'),
70        'form.scd_sit_fname': _(u'Second Sitting Record'),
71        'form.alr_fname': _(u'Advanced Level Record'),
72        'form.hq_type': _(u'Higher Education Record'),
73        'form.hq2_type': _(u'Second Higher Education Record'),
74        'form.nysc_year': _(u'NYSC Information'),
75        'form.employer': _(u'Employment History'),
76        'form.former_matric': _(u'Former Student'),
77        'form.fever': _(u'History of Symptoms'),
78        'form.asthma': _(u'Medical History'),
79        'form.lagos_abuja': _(u'Travel History'),
80        'form.company_suspected': _(u'History of Contact/Infection'),
81        'form.genotype': _(u'TISHIP Registration Form Data'),
82        }
83
84    def getReturningData(self, student):
85        """ This method defines what happens after school fee payment
86        of returning students depending on the student's senate verdict.
87        """
88        prev_level = student['studycourse'].current_level
89        cur_verdict = student['studycourse'].current_verdict
90        if cur_verdict == 'N' and prev_level in (100, 200):
91            new_level = prev_level
92        elif cur_verdict in ('A','B','L','M','N','Z',):
93            # Successful student
94            new_level = divmod(int(prev_level),100)[0]*100 + 100
95        elif cur_verdict == 'C':
96            # Student on probation
97            new_level = int(prev_level) + 10
98        else:
99            # Student is somehow in an undefined state.
100            # Level has to be set manually.
101            new_level = prev_level
102        new_session = student['studycourse'].current_session + 1
103        return new_session, new_level
104
105
106    def checkAccommodationRequirements(self, student, acc_details):
107        if acc_details.get('expired', False):
108            startdate = acc_details.get('startdate')
109            enddate = acc_details.get('enddate')
110            if startdate and enddate:
111                tz = getUtility(IKofaUtils).tzinfo
112                startdate = to_timezone(
113                    startdate, tz).strftime("%d/%m/%Y %H:%M:%S")
114                enddate = to_timezone(
115                    enddate, tz).strftime("%d/%m/%Y %H:%M:%S")
116                return _("Outside booking period: ${a} - ${b}",
117                         mapping = {'a': startdate, 'b': enddate})
118            else:
119                return _("Outside booking period.")
120        if not student.is_postgrad and student.current_mode != 'ug_ft':
121            return _("Only undergraduate full-time students are eligible to book accommodation.")
122        bt = acc_details.get('bt')
123        if not bt:
124            return _("Your data are incomplete.")
125        if not student.state in acc_details['allowed_states']:
126            return _("You are in the wrong registration state.")
127        #if student['studycourse'].current_session != acc_details[
128        #    'booking_session']:
129        #    return _('Your current session does not '
130        #             'match accommodation session.')
131        if  acc_details['booking_session'] - student[
132            'studycourse'].current_session > self.ACCOMMODATION_SPAN:
133            return _('Your current session does not allow ' + \
134                    'to book accommodation.')
135        stage = bt.split('_')[2]
136        if not student.is_postgrad and stage != 'fr' and not student[
137            'studycourse'].previous_verdict in (
138                'A', 'B', 'F', 'J', 'L', 'M', 'C', 'Z'):
139            return _("Your are not eligible to book accommodation.")
140        bsession = str(acc_details['booking_session'])
141        if bsession in student['accommodation'].keys() \
142            and not 'booking expired' in \
143            student['accommodation'][bsession].bed_coordinates:
144            return _('You already booked a bed space in '
145                     'current accommodation session.')
146        return
147
148    def getAccommodationDetails(self, student):
149        """Determine the accommodation data of a student.
150        """
151        d = {}
152        d['error'] = u''
153        hostels = grok.getSite()['hostels']
154        d['booking_session'] = hostels.accommodation_session
155        d['allowed_states'] = hostels.accommodation_states
156        d['startdate'] = hostels.startdate
157        d['enddate'] = hostels.enddate
158        d['expired'] = hostels.expired
159        # Determine bed type
160        studycourse = student['studycourse']
161        certificate = getattr(studycourse,'certificate',None)
162        entry_session = studycourse.entry_session
163        current_level = studycourse.current_level
164        if None in (entry_session, current_level, certificate):
165            return d
166        if student.sex == 'f':
167            sex = 'female'
168        else:
169            sex = 'male'
170        if student.is_postgrad:
171            bt = 'all'
172            special_handling = 'pg'
173        else:
174            end_level = certificate.end_level
175            if current_level == 10:
176                bt = 'pr'
177            elif entry_session == grok.getSite()['hostels'].accommodation_session:
178                bt = 'fr'
179            elif current_level >= end_level:
180                bt = 'fi'
181            else:
182                bt = 're'
183            special_handling = 'regular'
184            desired_hostel = student['accommodation'].desired_hostel
185            if student.faccode in ('MED', 'DEN') and (
186                not desired_hostel or desired_hostel.startswith('clinical')):
187                special_handling = 'clinical'
188            elif student.certcode in ('BARTMAS', 'BARTTHR', 'BARTFAA',
189                                      'BAEDFAA', 'BSCEDECHED', 'BAFAA',
190                                      'BARTMUS', 'BSCEDECHED'):
191                special_handling = 'ekenwan'
192        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
193        return d
194
195    def _paymentMade(self, student, session):
196        if len(student['payments']):
197            for ticket in student['payments'].values():
198                if ticket.p_state == 'paid' and \
199                    ticket.p_category == 'schoolfee' and \
200                    ticket.p_session == session:
201                    return True
202        return False
203
204    def _isPaymentDisabled(self, p_session, category, student):
205        academic_session = self._getSessionConfiguration(p_session)
206        if category == 'schoolfee':
207            if 'sf_all' in academic_session.payment_disabled:
208                return True
209            if student.state == RETURNING and \
210                'sf_return' in academic_session.payment_disabled:
211                return True
212            if student.current_mode == 'found' and \
213                'sf_found' in academic_session.payment_disabled:
214                return True
215            if student.is_postgrad:
216                if 'sf_pg' in academic_session.payment_disabled:
217                    return True
218                return False
219            if student.current_mode.endswith('ft') and \
220                'sf_ft' in academic_session.payment_disabled:
221                return True
222            if student.current_mode.endswith('pt') and \
223                'sf_pt' in academic_session.payment_disabled:
224                return True
225            if student.current_mode.startswith('dp') and \
226                'sf_dp' in academic_session.payment_disabled:
227                return True
228            if student.current_mode.endswith('sw') and \
229                'sf_sw' in academic_session.payment_disabled:
230                return True
231        if category == 'hostel_maintenance' and \
232            'maint_all' in academic_session.payment_disabled:
233            return True
234        if category == 'clearance':
235            if 'cl_all' in academic_session.payment_disabled:
236                return True
237            if student.is_jupeb and \
238                'cl_jupeb' in academic_session.payment_disabled:
239                return True
240            if not student.is_jupeb and \
241                'cl_allexj' in academic_session.payment_disabled:
242                return True
243        return False
244
245    #def _hostelApplicationPaymentMade(self, student, session):
246    #    if len(student['payments']):
247    #        for ticket in student['payments'].values():
248    #            if ticket.p_state == 'paid' and \
249    #                ticket.p_category == 'hostel_application' and \
250    #                ticket.p_session == session:
251    #                return True
252    #    return False
253
254    def _pharmdInstallments(self, student):
255        installments = 0.0
256        if len(student['payments']):
257            for ticket in student['payments'].values():
258                if ticket.p_state == 'paid' and \
259                    ticket.p_category.startswith('pharmd') and \
260                    ticket.p_session == student.current_session:
261                    installments += ticket.amount_auth
262        return installments
263
264    def samePaymentMade(self, student, category, p_item, p_session):
265        if category in ('bed_allocation', 'transcript'):
266            return False
267        for key in student['payments'].keys():
268            ticket = student['payments'][key]
269            if ticket.p_state == 'paid' and\
270               ticket.p_category == category and \
271               ticket.p_item == p_item and \
272               ticket.p_session == p_session:
273                  return True
274        return False
275
276    def setPaymentDetails(self, category, student,
277            previous_session, previous_level, combi):
278        """Create Payment object and set the payment data of a student for
279        the payment category specified.
280
281        """
282        p_item = u''
283        amount = 0.0
284        if previous_session:
285            if previous_session < student['studycourse'].entry_session:
286                return _('The previous session must not fall below '
287                         'your entry session.'), None
288            if category == 'schoolfee':
289                # School fee is always paid for the following session
290                if previous_session > student['studycourse'].current_session:
291                    return _('This is not a previous session.'), None
292            else:
293                if previous_session > student['studycourse'].current_session - 1:
294                    return _('This is not a previous session.'), None
295            p_session = previous_session
296            p_level = previous_level
297            p_current = False
298        else:
299            p_session = student['studycourse'].current_session
300            p_level = student['studycourse'].current_level
301            p_current = True
302        academic_session = self._getSessionConfiguration(p_session)
303        if academic_session == None:
304            return _(u'Session configuration object is not available.'), None
305        # Determine fee.
306        if category.startswith('pharmd') \
307            and student.current_mode == 'special_ft':
308            amount = 80000.0
309        elif category == 'plag_test':
310            amount = 2500.0
311            if student.is_postgrad:
312                amount = 5000.0
313        #elif category == 'develop' and student.is_postgrad:
314        #    amount = academic_session.development_fee
315        elif category == 'bed_allocation':
316            acco_details = self.getAccommodationDetails(student)
317            p_session = acco_details['booking_session']
318            p_item = acco_details['bt']
319            desired_hostel = student['accommodation'].desired_hostel
320            if not desired_hostel:
321                return _(u'Select your favoured hostel first.'), None
322            if desired_hostel and desired_hostel != 'no':
323                p_item = u'%s (%s)' % (p_item, desired_hostel)
324            amount = academic_session.booking_fee
325            if student.is_postgrad:
326                amount += 500
327        elif category == 'hostel_maintenance':
328            amount = 0.0
329            booking_session = grok.getSite()['hostels'].accommodation_session
330            bedticket = student['accommodation'].get(str(booking_session), None)
331            if bedticket is not None and bedticket.bed is not None:
332                p_item = bedticket.bed_coordinates
333                p_session = booking_session
334                if bedticket.bed.__parent__.maint_fee > 0:
335                    amount = bedticket.bed.__parent__.maint_fee
336                else:
337                    # fallback
338                    amount = academic_session.maint_fee
339            else:
340                return _(u'No bed allocated.'), None
341        #elif category == 'hostel_application':
342        #    amount = 1000.0
343        #elif category.startswith('tempmaint'):
344        #    if not self._hostelApplicationPaymentMade(
345        #        student, student.current_session):
346        #        return _(
347        #            'You have not yet paid the hostel application fee.'), None
348        #    if category == 'tempmaint_1':
349        #        amount = 8150.0
350        #    elif category == 'tempmaint_2':
351        #        amount = 12650.0
352        #    elif category == 'tempmaint_3':
353        #        amount = 9650.0
354        elif category == 'clearance':
355            p_item = student.certcode
356            if p_item is None:
357                return _('Study course data are incomplete.'), None
358            if student.is_jupeb:
359                amount = 50000.0
360            elif student.faccode.startswith('FCETA'):
361                # ASABA and AKOKA
362                amount = 35000.0
363            elif student.depcode == 'DMIC':
364                amount = 70000.0
365            elif student.faccode in ('BMS', 'MED', 'DEN') \
366                and not student.is_postgrad:
367                amount = 80000.0
368            elif student.faccode == 'DCOEM':
369                return _('Acceptance fee payment not necessary.'), None
370            else:
371                amount = 60000.0
372        elif category == 'schoolfee':
373            try:
374                certificate = student['studycourse'].certificate
375                p_item = certificate.code
376            except (AttributeError, TypeError):
377                return _('Study course data are incomplete.'), None
378            try:
379                if student.entry_session < 2017:
380                    schoolfees_dict = SCHOOLFEES[12][p_item]
381                elif student.entry_session < 2020:
382                    schoolfees_dict = SCHOOLFEES[17][p_item]
383                elif student.entry_session < 2022:
384                    schoolfees_dict = SCHOOLFEES[20][p_item]
385                else:
386                    schoolfees_dict = SCHOOLFEES[22][p_item]
387            except KeyError:
388                return _('School fee not yet fixed: p_item = %s' % p_item), None
389            if previous_session:
390                # Students can pay for previous sessions in all workflow states.
391                # Fresh students are excluded by the update method of the
392                # PreviousPaymentAddFormPage.
393                if previous_session == student['studycourse'].entry_session:
394                    if student.is_foreigner:
395                        amount = schoolfees_dict['initial_foreigner']
396                    else:
397                        amount = schoolfees_dict['initial']
398                else:
399                    if student.is_foreigner:
400                        amount = schoolfees_dict['returning_foreigner']
401                    else:
402                        amount = schoolfees_dict['returning']
403            else:
404                if student.state == CLEARED:
405                    if student.is_foreigner:
406                        amount = schoolfees_dict['initial_foreigner']
407                    else:
408                        amount = schoolfees_dict['initial']
409                elif student.state == PAID and student.is_postgrad:
410                    p_session += 1
411                    academic_session = self._getSessionConfiguration(p_session)
412                    if academic_session == None:
413                        return _(u'Session configuration object is not available.'), None
414                    if student.is_foreigner:
415                        amount = schoolfees_dict['returning_foreigner']
416                    else:
417                        amount = schoolfees_dict['returning']
418                elif student.state == RETURNING:
419                    # In case of returning school fee payment the payment session
420                    # and level contain the values of the session the student
421                    # has paid for.
422                    p_session, p_level = self.getReturningData(student)
423                    academic_session = self._getSessionConfiguration(p_session)
424                    if academic_session == None:
425                        return _(u'Session configuration object is not available.'), None
426
427                    # Students are only allowed to pay for the next session
428                    # if current session payment has really been made,
429                    # i.e. payment object exists and is paid.
430                    #if not self._paymentMade(
431                    #    student, student.current_session):
432                    #    return _('You have not yet paid your current/active' +
433                    #             ' session. Please use the previous session' +
434                    #             ' payment form first.'), None
435
436                    if student.is_foreigner:
437                        amount = schoolfees_dict['returning_foreigner']
438                    else:
439                        amount = schoolfees_dict['returning']
440                # PHARMD school fee amount is fixed and previously paid
441                # installments in current session are deducted.
442                if student.current_mode == 'special_ft' \
443                    and student.state in (RETURNING, CLEARED):
444                    if student.is_foreigner:
445                        amount = 260000.0 - self._pharmdInstallments(student)
446                    else:
447                        amount = 160000.0 - self._pharmdInstallments(student)
448            try:
449                amount = float(amount)
450            except ValueError:
451                return _(u'School fee not yet fixed: p_item = %s' % p_item), None
452            # Give 50% school fee discount to staff members.
453            if student.is_staff:
454                amount /= 2
455
456        else:
457            fee_name = category + '_fee'
458            amount = getattr(academic_session, fee_name, 0.0)
459        if amount in (0.0, None):
460            return _('Amount could not be determined.'), None
461        # Add session specific penalty fee.
462        if category == 'schoolfee' and student.is_postgrad:
463            amount += academic_session.penalty_pg
464            amount += academic_session.development_fee
465        elif category == 'schoolfee' and student.current_mode == ('ug_ft'):
466            amount += academic_session.penalty_ug_ft
467        elif category == 'schoolfee' and student.current_mode == ('ug_pt'):
468            amount += academic_session.penalty_ug_pt
469        elif category == 'schoolfee' and student.current_mode == ('ug_sw'):
470            amount += academic_session.penalty_sw
471        elif category == 'schoolfee' and student.current_mode in (
472            'dp_ft', 'dp_pt'):
473            amount += academic_session.penalty_dp
474        if category.startswith('tempmaint'):
475            p_item = getUtility(IKofaUtils).PAYMENT_CATEGORIES[category]
476            p_item = unicode(p_item)
477            # Now we change the category because tempmaint payments
478            # will be obsolete when Uniben returns to Kofa bed allocation.
479            category = 'hostel_maintenance'
480        # Create ticket.
481        if self.samePaymentMade(student, category, p_item, p_session):
482            return _('This type of payment has already been made.'), None
483        if self._isPaymentDisabled(p_session, category, student):
484            return _('This category of payments has been disabled.'), None
485        payment = createObject(u'waeup.StudentOnlinePayment')
486        timestamp = ("%d" % int(time()*10000))[1:]
487        payment.p_id = "p%s" % timestamp
488        payment.p_category = category
489        payment.p_item = p_item
490        payment.p_session = p_session
491        payment.p_level = p_level
492        payment.p_current = p_current
493        payment.amount_auth = amount
494        return None, payment
495
496    def warnCreditsOOR(self, studylevel, course=None):
497        studycourse = studylevel.__parent__
498        certificate = getattr(studycourse,'certificate', None)
499        current_level = studycourse.current_level
500        if None in (current_level, certificate):
501            return
502        if studylevel.__parent__.previous_verdict == 'R':
503            return
504        end_level = certificate.end_level
505        if studylevel.student.faccode in (
506            'MED', 'DEN', 'BMS') and studylevel.level == 200:
507            limit = 61
508        elif current_level >= end_level:
509            limit = 51
510        else:
511            limit = 50
512        if course and studylevel.total_credits + course.credits > limit:
513            return _('Maximum credits exceeded.')
514        elif studylevel.total_credits > limit:
515            return _('Maximum credits exceeded.')
516        return
517
518    def warnCourseAlreadyPassed(self, studylevel, course):
519        """Return message if course has already been passed at
520        previous levels.
521        """
522
523        # med: we may need to put this matter on hold and allow
524        # all the students to register.
525        return False
526
527        previous_verdict = studylevel.__parent__.previous_verdict
528        if previous_verdict in ('C', 'M'):
529            return False
530        for slevel in studylevel.__parent__.values():
531            for cticket in slevel.values():
532                if cticket.code == course.code \
533                    and cticket.total_score >= cticket.passmark:
534                    return _('Course has already been passed at previous level.')
535        return False
536
537    def clearance_disabled_message(self, student):
538        if student.is_postgrad:
539            return None
540        try:
541            session_config = grok.getSite()[
542                'configuration'][str(student.current_session)]
543        except KeyError:
544            return _('Session configuration object is not available.')
545        if not session_config.clearance_enabled:
546            return _('Clearance is disabled for this session.')
547        return None
548
549    def renderPDFTranscript(self, view, filename='transcript.pdf',
550                  student=None,
551                  studentview=None,
552                  note=None,
553                  signatures=(),
554                  sigs_in_footer=(),
555                  digital_sigs=(),
556                  show_scans=True, topMargin=1.5,
557                  omit_fields=(),
558                  tableheader=None,
559                  no_passport=False,
560                  save_file=False):
561        """Render pdf slip of a transcripts.
562        """
563        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
564        # XXX: tell what the different parameters mean
565        style = getSampleStyleSheet()
566        creator = self.getPDFCreator(student)
567        data = []
568        doc_title = view.label
569        author = '%s (%s)' % (view.request.principal.title,
570                              view.request.principal.id)
571        footer_text = view.label.split('\n')
572        if len(footer_text) > 2:
573            # We can add a department in first line
574            footer_text = footer_text[1]
575        else:
576            # Only the first line is used for the footer
577            footer_text = footer_text[0]
578        if getattr(student, 'student_id', None) is not None:
579            footer_text = "%s - %s - " % (student.student_id, footer_text)
580
581        # Insert student data table
582        if student is not None:
583            #bd_translation = trans(_('Base Data'), portal_language)
584            #data.append(Paragraph(bd_translation, HEADING_STYLE))
585            data.append(render_student_data(
586                studentview, view.context,
587                omit_fields, lang=portal_language,
588                slipname=filename,
589                no_passport=no_passport))
590
591        transcript_data = view.context.getTranscriptData()
592        levels_data = transcript_data[0]
593
594        contextdata = []
595        f_label = trans(_('Course of Study:'), portal_language)
596        f_label = Paragraph(f_label, ENTRY1_STYLE)
597        f_text = formatted_text(view.context.certificate.longtitle)
598        f_text = Paragraph(f_text, ENTRY1_STYLE)
599        contextdata.append([f_label,f_text])
600
601        f_label = trans(_('Faculty:'), portal_language)
602        f_label = Paragraph(f_label, ENTRY1_STYLE)
603        f_text = formatted_text(
604            view.context.certificate.__parent__.__parent__.__parent__.longtitle)
605        f_text = Paragraph(f_text, ENTRY1_STYLE)
606        contextdata.append([f_label,f_text])
607
608        f_label = trans(_('Department:'), portal_language)
609        f_label = Paragraph(f_label, ENTRY1_STYLE)
610        f_text = formatted_text(
611            view.context.certificate.__parent__.__parent__.longtitle)
612        f_text = Paragraph(f_text, ENTRY1_STYLE)
613        contextdata.append([f_label,f_text])
614
615        f_label = trans(_('Entry Session:'), portal_language)
616        f_label = Paragraph(f_label, ENTRY1_STYLE)
617        f_text = formatted_text(
618            view.session_dict.get(view.context.entry_session))
619        f_text = Paragraph(f_text, ENTRY1_STYLE)
620        contextdata.append([f_label,f_text])
621
622        f_label = trans(_('Final Session:'), portal_language)
623        f_label = Paragraph(f_label, ENTRY1_STYLE)
624        f_text = formatted_text(
625            view.session_dict.get(view.context.current_session))
626        f_text = Paragraph(f_text, ENTRY1_STYLE)
627        contextdata.append([f_label,f_text])
628
629        f_label = trans(_('Entry Mode:'), portal_language)
630        f_label = Paragraph(f_label, ENTRY1_STYLE)
631        f_text = formatted_text(view.studymode_dict.get(
632            view.context.entry_mode))
633        f_text = Paragraph(f_text, ENTRY1_STYLE)
634        contextdata.append([f_label,f_text])
635
636        f_label = trans(_('Final Verdict:'), portal_language)
637        f_label = Paragraph(f_label, ENTRY1_STYLE)
638        f_text = formatted_text(view.studymode_dict.get(
639            view.context.current_verdict))
640        f_text = Paragraph(f_text, ENTRY1_STYLE)
641        contextdata.append([f_label,f_text])
642
643        f_label = trans(_('Cumulative GPA:'), portal_language)
644        f_label = Paragraph(f_label, ENTRY1_STYLE)
645        format_float = getUtility(IKofaUtils).format_float
646        cgpa = format_float(transcript_data[1], 3)
647        if student.state == GRADUATED:
648            f_text = formatted_text('%s (%s)' % (
649                cgpa, self.getClassFromCGPA(transcript_data[1], student)[1]))
650        else:
651            f_text = formatted_text('%s' % cgpa)
652        f_text = Paragraph(f_text, ENTRY1_STYLE)
653        contextdata.append([f_label,f_text])
654
655        contexttable = Table(contextdata,style=SLIP_STYLE)
656        data.append(contexttable)
657
658        transcripttables = render_transcript_data(
659            view, tableheader, levels_data, lang=portal_language)
660        data.extend(transcripttables)
661
662        # Insert signatures
663        # XXX: We are using only sigs_in_footer in waeup.kofa, so we
664        # do not have a test for the following lines.
665        if signatures and not sigs_in_footer:
666            data.append(Spacer(1, 20))
667            # Render one signature table per signature to
668            # get date and signature in line.
669            for signature in signatures:
670                signaturetables = get_signature_tables(signature)
671                data.append(signaturetables[0])
672
673        # Insert digital signatures
674        if digital_sigs:
675            data.append(Spacer(1, 20))
676            sigs = digital_sigs.split('\n')
677            for sig in sigs:
678                data.append(Paragraph(sig, NOTE_STYLE))
679
680        view.response.setHeader(
681            'Content-Type', 'application/pdf')
682        try:
683            pdf_stream = creator.create_pdf(
684                data, None, doc_title, author=author, footer=footer_text,
685                note=note, sigs_in_footer=sigs_in_footer, topMargin=topMargin,
686                view=view)
687        except IOError:
688            view.flash(_('Error in image file.'))
689            return view.redirect(view.url(view.context))
690        if save_file:
691            self._saveTranscriptPDF(student, pdf_stream)
692            return
693        return pdf_stream
694
695    #: A tuple containing the names of registration states in which changing of
696    #: passport pictures is allowed.
697    PORTRAIT_CHANGE_STATES = (CLEARANCE, REQUESTED)
698
699    #: A tuple containing the names of registration states in which changing of
700    #: scanned signatures is allowed.
701    SIGNATURE_CHANGE_STATES = (CLEARED, RETURNING, PAID, REGISTERED, VALIDATED, )
702
703    # Uniben prefix
704    @property
705    def STUDENT_ID_PREFIX(self):
706        if grok.getSite().__name__ == 'uniben-cdl':
707            return u'C'
708        return u'B'
709
710    STUDENT_EXPORTER_NAMES = (
711            'students',
712            'studentstudycourses',
713            'studentstudycourses_1',
714            'studentstudylevels',
715            #'studentstudylevels_1',
716            'coursetickets',
717            #'coursetickets_1',
718            'studentpayments',
719            'bedtickets',
720            'trimmed',
721            'outstandingcourses',
722            'unpaidpayments',
723            'sfpaymentsoverview',
724            'sessionpaymentsoverview',
725            'studylevelsoverview',
726            'combocard',
727            'bursary',
728            'accommodationpayments',
729            'transcriptdata',
730            'trimmedpayments',
731            'medicalhistory',
732            'nysc',
733            )
Note: See TracBrowser for help on using the repository browser.