source: main/waeup.aaue/trunk/src/waeup/aaue/students/utils.py @ 16673

Last change on this file since 16673 was 16672, checked in by Henrik Bettermann, 3 years ago

Customize allowPortraitChange.

  • Property svn:keywords set to Id
File size: 27.6 KB
Line 
1## $Id: utils.py 16672 2021-10-07 11:13:12Z 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 zope.component import createObject, queryUtility
21from zope.catalog.interfaces import ICatalog
22from waeup.kofa.interfaces import (
23    ADMITTED, CLEARANCE, REQUESTED, CLEARED, RETURNING, PAID,
24    REGISTERED, VALIDATED, academic_sessions_vocab)
25from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
26from waeup.kofa.accesscodes import create_accesscode
27from waeup.kofa.students.utils import trans
28from waeup.aaue.interswitch.browser import gateway_net_amt, GATEWAY_AMT
29from waeup.aaue.interfaces import MessageFactory as _
30
31MINIMUM_UNITS_THRESHOLD = 15
32
33class CustomStudentsUtils(NigeriaStudentsUtils):
34    """A collection of customized methods.
35
36    """
37
38    # PORTRAIT_CHANGE_STATES = (ADMITTED, CLEARANCE, REQUESTED, CLEARED)
39
40    def allowPortraitChange(self, student):
41        if student.is_fresh:
42            return True
43        return False
44
45    def GPABoundaries(self, faccode=None, depcode=None,
46                            certcode=None, student=None):
47        if student and student.current_mode.startswith('dp'):
48            return ((1.5, 'IRNS / NER / NYV'),
49                    (2.4, 'Pass'),
50                    (3.5, 'Merit'),
51                    (4.5, 'Credit'),
52                    (5, 'Distinction'))
53        elif student:
54            return ((1, 'FRNS / NER / NYV'),
55                    (1.5, 'Pass'),
56                    (2.4, '3rd Class Honours'),
57                    (3.5, '2nd Class Honours Lower Division'),
58                    (4.5, '2nd Class Honours Upper Division'),
59                    (5, '1st Class Honours'))
60        # Session Results Presentations depend on certificate
61        results = None
62        if certcode:
63            cat = queryUtility(ICatalog, name='certificates_catalog')
64            results = list(
65                cat.searchResults(code=(certcode, certcode)))
66        if results and results[0].study_mode.startswith('dp'):
67            return ((1.5, 'IRNS / NER / NYV'),
68                    (2.4, 'Pass'),
69                    (3.5, 'Merit'),
70                    (4.5, 'Credit'),
71                    (5, 'Distinction'))
72        else:
73            return ((1, 'FRNS / NER / NYV'),
74                    (1.5, 'Pass'),
75                    (2.4, '3rd Class Honours'),
76                    (3.5, '2nd Class Honours Lower Division'),
77                    (4.5, '2nd Class Honours Upper Division'),
78                    (5, '1st Class Honours'))
79
80    def getClassFromCGPA(self, gpa, student):
81        gpa_boundaries = self.GPABoundaries(student=student)
82
83        try:
84            certificate = getattr(student['studycourse'],'certificate',None)
85            end_level = getattr(certificate, 'end_level', None)
86            final_level = max([studylevel.level for studylevel in student['studycourse'].values()])
87            if end_level and final_level >= end_level:
88                dummy, repeat = divmod(final_level, 100)
89                if gpa <= 5.1 and repeat == 20:
90                    # Irrespective of the CGPA of a student, if the He/She has
91                    # 3rd Extension, such student will be graduated with a "Pass".
92                    return 1, gpa_boundaries[1][1]
93        except ValueError:
94            pass
95
96        if gpa < gpa_boundaries[0][0]:
97            # FRNS / Fail
98            return 0, gpa_boundaries[0][1]
99        if student.entry_session < 2013 or \
100            student.current_mode.startswith('dp'):
101            if gpa < gpa_boundaries[1][0]:
102                # Pass
103                return 1, gpa_boundaries[1][1]
104        else:
105            if gpa < gpa_boundaries[1][0]:
106                # FRNS
107                # Pass degree has been phased out in 2013 for non-diploma
108                # students
109                return 0, gpa_boundaries[0][1]
110        if gpa < gpa_boundaries[2][0]:
111            # 3rd / Merit
112            return 2, gpa_boundaries[2][1]
113        if gpa < gpa_boundaries[3][0]:
114            # 2nd L / Credit
115            return 3, gpa_boundaries[3][1]
116        if gpa < gpa_boundaries[4][0]:
117            # 2nd U / Distinction
118            return 4, gpa_boundaries[4][1]
119        if gpa <= gpa_boundaries[5][0]:
120            # 1st
121            return 5, gpa_boundaries[5][1]
122        return
123
124    def getDegreeClassNumber(self, level_obj):
125        """Get degree class number (used for SessionResultsPresentation
126        reports).
127        """
128        certificate = getattr(level_obj.__parent__,'certificate', None)
129        end_level = getattr(certificate, 'end_level', None)
130        if level_obj.gpa_params[1] < MINIMUM_UNITS_THRESHOLD:
131            # credits taken below limit
132            return 0
133        if end_level and level_obj.level >= end_level:
134            failed_courses = level_obj.passed_params[4]
135            not_taken_courses = level_obj.passed_params[5]
136            if '_m' in failed_courses:
137                return 0
138            if len(not_taken_courses) \
139                and not not_taken_courses == 'Nil':
140                return 0
141        if level_obj.level_verdict in ('FRNS', 'NER', 'NYV'):
142            return 0
143        # use gpa_boundaries above
144        return self.getClassFromCGPA(
145            level_obj.cumulative_params[0], level_obj.student)[0]
146
147    def increaseMatricInteger(self, student):
148        """Increase counter for matric numbers.
149        This counter can be a centrally stored attribute or an attribute of
150        faculties, departments or certificates. In the base package the counter
151        is as an attribute of the site configuration container.
152        """
153        if student.current_mode in ('ug_pt', 'de_pt', 'ug_dsh', 'de_dsh'):
154            grok.getSite()['configuration'].next_matric_integer += 1
155            return
156        elif student.is_postgrad:
157            grok.getSite()['configuration'].next_matric_integer_3 += 1
158            return
159        elif student.current_mode in ('dp_ft',):
160            grok.getSite()['configuration'].next_matric_integer_4 += 1
161            return
162        grok.getSite()['configuration'].next_matric_integer_2 += 1
163        return
164
165    def _concessionalPaymentMade(self, student):
166        if len(student['payments']):
167            for ticket in student['payments'].values():
168                if ticket.p_state == 'paid' and \
169                    ticket.p_category == 'concessional':
170                    return True
171        return False
172
173    def constructMatricNumber(self, student):
174        faccode = student.faccode
175        depcode = student.depcode
176        certcode = student.certcode
177        degree = getattr(
178            getattr(student.get('studycourse', None), 'certificate', None),
179                'degree', None)
180        year = unicode(student.entry_session)[2:]
181        if not student.state in (PAID, ) or not student.is_fresh or \
182            student.current_mode in ('found', 'ijmbe'):
183            return _('Matriculation number cannot be set.'), None
184        #if student.current_mode not in ('mug_ft', 'mde_ft') and \
185        #    not self._concessionalPaymentMade(student):
186        #    return _('Matriculation number cannot be set.'), None
187        if student.is_postgrad:
188            next_integer = grok.getSite()['configuration'].next_matric_integer_3
189            if not degree or next_integer == 0:
190                return _('Matriculation number cannot be set.'), None
191            if student.faccode in ('IOE'):
192                return None, "AAU/SPS/%s/%s/%s/%05d" % (
193                    faccode, year, degree, next_integer)
194            return None, "AAU/SPS/%s/%s/%s/%s/%05d" % (
195                faccode, depcode, year, degree, next_integer)
196        if student.current_mode in ('ug_dsh', 'de_dsh'):
197            next_integer = grok.getSite()['configuration'].next_matric_integer
198            if next_integer == 0:
199                return _('Matriculation number cannot be set.'), None
200            return None, "DSH/%s/%s/%s/%05d" % (
201                faccode, depcode, year, next_integer)
202        if student.current_mode in ('ug_pt', 'de_pt'):
203            next_integer = grok.getSite()['configuration'].next_matric_integer
204            if next_integer == 0:
205                return _('Matriculation number cannot be set.'), None
206            return None, "PTP/%s/%s/%s/%05d" % (
207                faccode, depcode, year, next_integer)
208        if student.current_mode in ('dp_ft',):
209            next_integer = grok.getSite()['configuration'].next_matric_integer_4
210            if next_integer == 0:
211                return _('Matriculation number cannot be set.'), None
212            return None, "IOE/DIP/%s/%05d" % (year, next_integer)
213        next_integer = grok.getSite()['configuration'].next_matric_integer_2
214        if next_integer == 0:
215            return _('Matriculation number cannot be set.'), None
216        if student.faccode in ('FBM', 'FCS'):
217            return None, "CMS/%s/%s/%s/%05d" % (
218                faccode, depcode, year, next_integer)
219        return None, "%s/%s/%s/%05d" % (faccode, depcode, year, next_integer)
220
221    def getReturningData(self, student):
222        """ This method defines what happens after school fee payment
223        of returning students depending on the student's senate verdict.
224        """
225        prev_level = student['studycourse'].current_level
226        cur_verdict = student['studycourse'].current_verdict
227        if cur_verdict in ('A','B','L','M','N','Z',):
228            # Successful student
229            new_level = divmod(int(prev_level),100)[0]*100 + 100
230        elif cur_verdict == 'C':
231            # Student on probation
232            new_level = int(prev_level) + 10
233        else:
234            # Student is somehow in an undefined state.
235            # Level has to be set manually.
236            new_level = prev_level
237        new_session = student['studycourse'].current_session + 1
238        return new_session, new_level
239
240    def _isPaymentDisabled(self, p_session, category, student):
241        academic_session = self._getSessionConfiguration(p_session)
242        if category.startswith('schoolfee'):
243            if 'sf_all' in academic_session.payment_disabled:
244                return True
245            if 'sf_pg' in academic_session.payment_disabled and \
246                student.is_postgrad:
247                return True
248            if 'sf_ug_pt' in academic_session.payment_disabled and \
249                student.current_mode in ('ug_pt', 'de_pt'):
250                return True
251            if 'sf_found' in academic_session.payment_disabled and \
252                student.current_mode == 'found':
253                return True
254        if category.startswith('clearance') and \
255            'cl_regular' in academic_session.payment_disabled and \
256            student.current_mode in ('ug_ft', 'de_ft', 'mug_ft', 'mde_ft'):
257            return True
258        if category == 'hostel_maintenance' and \
259            'maint_all' in academic_session.payment_disabled:
260            return True
261        return False
262
263    def setPaymentDetails(self, category, student,
264            previous_session=None, previous_level=None, combi=[]):
265        """Create Payment object and set the payment data of a student for
266        the payment category specified.
267
268        """
269        details = {}
270        p_item = u''
271        amount = 0.0
272        error = u''
273        if previous_session:
274            if previous_session < student['studycourse'].entry_session:
275                return _('The previous session must not fall below '
276                         'your entry session.'), None
277            if category == 'schoolfee':
278                # School fee is always paid for the following session
279                if previous_session > student['studycourse'].current_session:
280                    return _('This is not a previous session.'), None
281            else:
282                if previous_session > student['studycourse'].current_session - 1:
283                    return _('This is not a previous session.'), None
284            p_session = previous_session
285            p_level = previous_level
286            p_current = False
287        else:
288            p_session = student['studycourse'].current_session
289            p_level = student['studycourse'].current_level
290            p_current = True
291        academic_session = self._getSessionConfiguration(p_session)
292        if academic_session == None:
293            return _(u'Session configuration object is not available.'), None
294        # Determine fee.
295        if category == 'transfer':
296            amount = academic_session.transfer_fee
297        elif category == 'transcript_local':
298            amount = academic_session.transcript_fee_local
299        elif category == 'transcript_inter':
300            amount = academic_session.transcript_fee_inter
301        elif category == 'bed_allocation':
302            amount = academic_session.booking_fee
303        elif category == 'restitution':
304            if student.current_session != 2016 \
305                or student.current_mode not in ('ug_ft', 'dp_ft') \
306                or student.is_fresh:
307                return _(u'Restitution fee payment not required.'), None
308            amount = academic_session.restitution_fee
309        elif category == 'hostel_maintenance':
310            amount = 0.0
311            bedticket = student['accommodation'].get(
312                str(student.current_session), None)
313            if bedticket is not None and bedticket.bed is not None:
314                p_item = bedticket.display_coordinates
315                if bedticket.bed.__parent__.maint_fee > 0:
316                    amount = bedticket.bed.__parent__.maint_fee
317                else:
318                    # fallback
319                    amount = academic_session.maint_fee
320            else:
321                return _(u'No bed allocated.'), None
322        elif student.current_mode == 'found' and category not in (
323            'schoolfee', 'clearance', 'late_registration'):
324            return _('Not allowed.'), None
325        elif category.startswith('clearance'):
326            if student.state not in (ADMITTED, CLEARANCE, REQUESTED, CLEARED):
327                return _(u'Acceptance Fee payments not allowed.'), None
328            if student.current_mode in (
329                'ug_ft', 'ug_pt', 'de_ft', 'de_pt',
330                'transfer', 'mug_ft', 'mde_ft') \
331                and category != 'clearance_incl':
332                    return _("Additional fees must be included."), None
333            if student.current_mode == 'ijmbe':
334                amount = academic_session.clearance_fee_ijmbe
335            elif student.current_mode == 'bridge':
336                amount = academic_session.clearance_fee_bridge
337            elif student.current_mode == 'dp_ft':
338                amount = academic_session.clearance_fee_dp
339            elif student.faccode == 'FP':
340                amount = academic_session.clearance_fee_fp
341            elif student.current_mode in ('ug_pt', 'de_pt', 'ug_dsh', 'de_dsh'):
342                amount = academic_session.clearance_fee_ug_pt
343            elif student.current_mode == 'special_pg_pt':
344                amount = academic_session.clearance_fee_pg_pt
345            elif student.faccode == 'FCS':
346                # Students in clinical medical sciences pay the medical
347                # acceptance fee
348                amount = academic_session.clearance_fee_med
349            elif student.current_mode == 'special_pg_ft':
350                if category != 'clearance':
351                    return _("No additional fees required."), None
352                amount = academic_session.clearance_fee_pg
353            else:
354                amount = academic_session.clearance_fee
355            p_item = student['studycourse'].certificate.code
356            if amount in (0.0, None):
357                return _(u'Amount could not be determined.'), None
358            # Add Matric Gown Fee and Lapel Fee
359            if category == 'clearance_incl':
360                amount += gateway_net_amt(academic_session.matric_gown_fee) + \
361                    gateway_net_amt(academic_session.lapel_fee)
362        elif category == 'late_registration':
363            if student.is_postgrad:
364                amount = academic_session.late_pg_registration_fee
365            else:
366                amount = academic_session.late_registration_fee
367        elif category == 'ict':
368            if student.is_fresh:
369                amount = 2200
370            else:
371                amount = 1200
372        elif category.startswith('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            if student.is_postgrad and category != 'schoolfee':
379                return _("No additional fees required."), None
380            if not previous_session and student.current_mode in (
381                'ug_ft', 'ug_pt', 'de_ft', 'de_pt',
382                'transfer', 'mug_ft', 'mde_ft') \
383                and not category in (
384                'schoolfee_incl', 'schoolfee_1', 'schoolfee_2'):
385                    return _("You must choose a payment which includes "
386                             "additional fees."), None
387            if category in ('schoolfee_1', 'schoolfee_2'):
388                if student.current_mode == 'ug_pt':
389                    return _("Part-time students are not allowed "
390                             "to pay by instalments."), None
391                if student.entry_session < 2015:
392                    return _("You are not allowed "
393                             "to pay by instalments."), None
394            if previous_session:
395                # Students can pay for previous sessions in all
396                # workflow states.  Fresh students are excluded by the
397                # update method of the PreviousPaymentAddFormPage.
398                if previous_level == 100:
399                    amount = getattr(certificate, 'school_fee_1', 0.0)
400                else:
401                    if student.entry_session in (2015, 2016):
402                        amount = getattr(certificate, 'school_fee_2', 0.0)
403                    else:
404                        amount = getattr(certificate, 'school_fee_3', 0.0)
405            elif student.state == CLEARED and category != 'schoolfee_2':
406                amount = getattr(certificate, 'school_fee_1', 0.0)
407                # Cut school fee by 50%
408                if category == 'schoolfee_1' and amount:
409                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
410            elif student.is_fresh and category == 'schoolfee_2':
411                amount = getattr(certificate, 'school_fee_1', 0.0)
412                # Cut school fee by 50%
413                if amount:
414                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
415            elif student.state == RETURNING and category != 'schoolfee_2':
416                if not student.father_name:
417                    return _("Personal data form is not properly filled."), None
418                # In case of returning school fee payment the payment session
419                # and level contain the values of the session the student
420                # has paid for.
421                p_session, p_level = self.getReturningData(student)
422                try:
423                    academic_session = grok.getSite()[
424                        'configuration'][str(p_session)]
425                except KeyError:
426                    return _(u'Session configuration object is not available.'), None
427                if student.entry_session >= 2015:
428                    amount = getattr(certificate, 'school_fee_2', 0.0)
429                else:
430                    amount = getattr(certificate, 'school_fee_3', 0.0)
431                # Cut school fee by 50%
432                if category == 'schoolfee_1' and amount:
433                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
434            elif category == 'schoolfee_2':
435                amount = getattr(certificate, 'school_fee_2', 0.0)
436                # Cut school fee by 50%
437                if amount:
438                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
439            else:
440                return _('Wrong state.'), None
441            if amount in (0.0, None):
442                return _(u'Amount could not be determined.'), None
443            # Add Student Union Fee, Student Id Card Fee, Sports Dev. Fee,
444            # Library Dev. Fee and Welfare Assurance
445            if category in ('schoolfee_incl', 'schoolfee_1') \
446                and student.current_mode != 'ijmbe':
447                amount += gateway_net_amt(academic_session.welfare_fee) + \
448                    gateway_net_amt(academic_session.union_fee)
449                if student.entry_session >= 2018 and student.is_fresh:
450                    amount += gateway_net_amt(academic_session.sports_fee)
451                    if student.is_postgrad:
452                        amount += gateway_net_amt(academic_session.library_pg_fee)
453                    else:
454                        amount += gateway_net_amt(academic_session.library_fee)
455            # Add non-indigenous fee and session specific penalty fees
456            if student.is_postgrad:
457                amount += academic_session.penalty_pg
458                if student.lga and not student.lga.startswith('edo'):
459                    amount += 20000.0
460            else:
461                amount += academic_session.penalty_ug
462        #elif category == ('fac_dep'):
463        #    if student.faccode in ('FAT', 'FED', 'FLW', 'FMS', 'FSS'):
464        #        amount = 4200.0
465        #    elif student.faccode in ('FAG', 'FBM', 'FCS',
466        #                             'FES', 'FET', 'FLS', 'FPS'):
467        #        amount = 5200.0
468        #    elif student.faccode == 'FAG' and student.current_level == 400:
469        #        amount = 10200.0
470        #    elif student.depcode == 'VTE':
471        #        amount = 5200.0
472        #    if student.entry_session >= 2019:
473        #        amount += gateway_net_amt(academic_session.ict_fee)
474        elif category == 'sports_library': # temporarily in 2020
475            if student.is_postgrad:
476                amount = academic_session.sports_fee + gateway_net_amt(
477                    academic_session.library_pg_fee)
478            else:
479                amount = academic_session.sports_fee + gateway_net_amt(
480                    academic_session.library_fee)
481        elif not student.is_postgrad:
482            fee_name = category + '_fee'
483            amount = getattr(academic_session, fee_name, 0.0)
484        if amount in (0.0, None):
485            return _(u'Amount could not be determined.'), None
486        # Create ticket.
487        for key in student['payments'].keys():
488            ticket = student['payments'][key]
489            if ticket.p_state == 'paid' and\
490               ticket.p_category == category and \
491               not ticket.p_category.startswith('transcript') and \
492               ticket.p_item == p_item and \
493               ticket.p_session == p_session:
494                  return _('This type of payment has already been made.'), None
495            # Additional condition in AAUE
496            if category in ('schoolfee', 'schoolfee_incl', 'schoolfee_1'):
497                if ticket.p_state == 'paid' and \
498                   ticket.p_category in ('schoolfee',
499                                         'schoolfee_incl',
500                                         'schoolfee_1') and \
501                   ticket.p_item == p_item and \
502                   ticket.p_session == p_session:
503                      return _(
504                          'Another school fee payment for this '
505                          'session has already been made.'), None
506
507        if self._isPaymentDisabled(p_session, category, student):
508            return _('This category of payments has been disabled.'), None
509        payment = createObject(u'waeup.StudentOnlinePayment')
510        timestamp = ("%d" % int(time()*10000))[1:]
511        payment.p_id = "p%s" % timestamp
512        payment.p_category = category
513        payment.p_item = p_item
514        payment.p_session = p_session
515        payment.p_level = p_level
516        payment.p_current = p_current
517        payment.amount_auth = amount
518        return None, payment
519
520    def _admissionText(self, student, portal_language):
521        inst_name = grok.getSite()['configuration'].name
522        entry_session = student['studycourse'].entry_session
523        entry_session = academic_sessions_vocab.getTerm(entry_session).title
524        text = trans(_(
525            'This is to inform you that you have been offered provisional'
526            ' admission into ${a} for the ${b} academic session as follows:',
527            mapping = {'a': inst_name, 'b': entry_session}),
528            portal_language)
529        return text
530
531    def warnCreditsOOR(self, studylevel, course=None):
532        studycourse = studylevel.__parent__
533        certificate = getattr(studycourse,'certificate', None)
534        current_level = studycourse.current_level
535        if None in (current_level, certificate):
536            return
537        end_level = certificate.end_level
538        if current_level >= end_level:
539            limit = 52
540        else:
541            limit = 48
542        if course and studylevel.total_credits + course.credits > limit:
543            return  _('Maximum credits exceeded.')
544        elif studylevel.total_credits > limit:
545            return _('Maximum credits exceeded.')
546        return
547
548    def getBedCoordinates(self, bedticket):
549        """Return descriptive bed coordinates.
550        This method can be used to customize the `display_coordinates`
551        property method in order to  display a
552        customary description of the bed space.
553        """
554        bc = bedticket.bed_coordinates.split(',')
555        if len(bc) == 4:
556            return bc[0]
557        return bedticket.bed_coordinates
558
559    def getAccommodationDetails(self, student):
560        """Determine the accommodation data of a student.
561        """
562        d = {}
563        d['error'] = u''
564        hostels = grok.getSite()['hostels']
565        d['booking_session'] = hostels.accommodation_session
566        d['allowed_states'] = hostels.accommodation_states
567        d['startdate'] = hostels.startdate
568        d['enddate'] = hostels.enddate
569        d['expired'] = hostels.expired
570        # Determine bed type
571        bt = 'all'
572        if student.sex == 'f':
573            sex = 'female'
574        else:
575            sex = 'male'
576        special_handling = 'regular'
577        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
578        return d
579
580    def checkAccommodationRequirements(self, student, acc_details):
581        msg = super(CustomStudentsUtils, self).checkAccommodationRequirements(
582            student, acc_details)
583        if msg:
584            return msg
585        if student.current_mode not in ('ug_ft', 'de_ft', 'mug_ft', 'mde_ft'):
586            return _('You are not eligible to book accommodation.')
587        return
588
589    # AAUE prefix
590    STUDENT_ID_PREFIX = u'E'
591
592    STUDENT_EXPORTER_NAMES = (
593            'students',
594            'studentstudycourses',
595            'studentstudylevels',
596            'coursetickets',
597            'studentpayments',
598            'bedtickets',
599            'unpaidpayments',
600            'sfpaymentsoverview',
601            'studylevelsoverview',
602            'combocard',
603            'bursary',
604            'levelreportdata',
605            'outstandingcourses',
606            'sessionpaymentsoverview',
607            'accommodationpayments',
608            'transcriptdata',
609            'trimmedpayments',
610            'trimmed',
611            )
612
613    # Maximum size of upload files in kB
614    MAX_KB = 500
Note: See TracBrowser for help on using the repository browser.