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

Last change on this file since 16389 was 16386, checked in by Henrik Bettermann, 4 years ago

Implement medical questionnaire fee.

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