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

Last change on this file since 17332 was 17266, checked in by Henrik Bettermann, 23 months ago

Adjust customized method according to changes in base package.

  • Property svn:keywords set to Id
File size: 27.8 KB
Line 
1## $Id: utils.py 17266 2023-01-11 07:18:08Z 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.level_verdict in ('FRNS', 'NER', 'NYV'):
131            return 0
132        if end_level and level_obj.level >= end_level:
133            if level_obj.level > end_level:
134                # spill-over level
135                if level_obj.gpa_params[1] == 0:
136                    # no credits taken
137                    return 0
138            elif level_obj.gpa_params[1] < MINIMUM_UNITS_THRESHOLD:
139                # credits taken below limit
140                return 0
141            failed_courses = level_obj.passed_params[4]
142            not_taken_courses = level_obj.passed_params[5]
143            if '_m' in failed_courses:
144                return 0
145            if len(not_taken_courses) \
146                and not not_taken_courses == 'Nil':
147                return 0
148        elif level_obj.gpa_params[1] < MINIMUM_UNITS_THRESHOLD:
149            # credits taken below limit
150            return 0
151        # use gpa_boundaries above
152        return self.getClassFromCGPA(
153            level_obj.cumulative_params[0], level_obj.student)[0]
154
155    def increaseMatricInteger(self, student):
156        """Increase counter for matric numbers.
157        This counter can be a centrally stored attribute or an attribute of
158        faculties, departments or certificates. In the base package the counter
159        is as an attribute of the site configuration container.
160        """
161        if student.current_mode in ('ug_pt', 'de_pt', 'ug_dsh', 'de_dsh'):
162            grok.getSite()['configuration'].next_matric_integer += 1
163            return
164        elif student.is_postgrad:
165            grok.getSite()['configuration'].next_matric_integer_3 += 1
166            return
167        elif student.current_mode in ('dp_ft',):
168            grok.getSite()['configuration'].next_matric_integer_4 += 1
169            return
170        grok.getSite()['configuration'].next_matric_integer_2 += 1
171        return
172
173    def _concessionalPaymentMade(self, student):
174        if len(student['payments']):
175            for ticket in student['payments'].values():
176                if ticket.p_state == 'paid' and \
177                    ticket.p_category == 'concessional':
178                    return True
179        return False
180
181    def constructMatricNumber(self, student):
182        faccode = student.faccode
183        depcode = student.depcode
184        certcode = student.certcode
185        degree = getattr(
186            getattr(student.get('studycourse', None), 'certificate', None),
187                'degree', None)
188        year = unicode(student.entry_session)[2:]
189        if not student.state in (PAID, ) or not student.is_fresh or \
190            student.current_mode in ('found', 'ijmbe'):
191            return _('Matriculation number cannot be set.'), None
192        #if student.current_mode not in ('mug_ft', 'mde_ft') and \
193        #    not self._concessionalPaymentMade(student):
194        #    return _('Matriculation number cannot be set.'), None
195        if student.is_postgrad:
196            next_integer = grok.getSite()['configuration'].next_matric_integer_3
197            if not degree or next_integer == 0:
198                return _('Matriculation number cannot be set.'), None
199            if student.faccode in ('IOE'):
200                return None, "AAU/SPS/%s/%s/%s/%05d" % (
201                    faccode, year, degree, next_integer)
202            return None, "AAU/SPS/%s/%s/%s/%s/%05d" % (
203                faccode, depcode, year, degree, next_integer)
204        if student.current_mode in ('ug_dsh', 'de_dsh'):
205            next_integer = grok.getSite()['configuration'].next_matric_integer
206            if next_integer == 0:
207                return _('Matriculation number cannot be set.'), None
208            return None, "DSH/%s/%s/%s/%05d" % (
209                faccode, depcode, year, next_integer)
210        if student.current_mode in ('ug_pt', 'de_pt'):
211            next_integer = grok.getSite()['configuration'].next_matric_integer
212            if next_integer == 0:
213                return _('Matriculation number cannot be set.'), None
214            return None, "PTP/%s/%s/%s/%05d" % (
215                faccode, depcode, year, next_integer)
216        if student.current_mode in ('dp_ft',):
217            next_integer = grok.getSite()['configuration'].next_matric_integer_4
218            if next_integer == 0:
219                return _('Matriculation number cannot be set.'), None
220            return None, "IOE/DIP/%s/%05d" % (year, next_integer)
221        next_integer = grok.getSite()['configuration'].next_matric_integer_2
222        if next_integer == 0:
223            return _('Matriculation number cannot be set.'), None
224        if student.faccode in ('FBM', 'FCS', 'FMLS'):
225            return None, "CMS/%s/%s/%s/%05d" % (
226                faccode, depcode, year, next_integer)
227        return None, "%s/%s/%s/%05d" % (faccode, depcode, year, next_integer)
228
229    def getReturningData(self, student):
230        """ This method defines what happens after school fee payment
231        of returning students depending on the student's senate verdict.
232        """
233        prev_level = student['studycourse'].current_level
234        cur_verdict = student['studycourse'].current_verdict
235        if cur_verdict in ('A','B','L','M','N','Z',):
236            # Successful student
237            new_level = divmod(int(prev_level),100)[0]*100 + 100
238        elif cur_verdict == 'C':
239            # Student on probation
240            new_level = int(prev_level) + 10
241        else:
242            # Student is somehow in an undefined state.
243            # Level has to be set manually.
244            new_level = prev_level
245        new_session = student['studycourse'].current_session + 1
246        return new_session, new_level
247
248    def _isPaymentDisabled(self, p_session, category, student):
249        academic_session = self._getSessionConfiguration(p_session)
250        if category.startswith('schoolfee'):
251            if 'sf_all' in academic_session.payment_disabled:
252                return True
253            if 'sf_pg' in academic_session.payment_disabled and \
254                student.is_postgrad:
255                return True
256            if 'sf_ug_pt' in academic_session.payment_disabled and \
257                student.current_mode in ('ug_pt', 'de_pt'):
258                return True
259            if 'sf_found' in academic_session.payment_disabled and \
260                student.current_mode == 'found':
261                return True
262        if category.startswith('clearance') and \
263            'cl_regular' in academic_session.payment_disabled and \
264            student.current_mode in ('ug_ft', 'de_ft', 'mug_ft', 'mde_ft'):
265            return True
266        if category == 'hostel_maintenance' and \
267            'maint_all' in academic_session.payment_disabled:
268            return True
269        return False
270
271    def setPaymentDetails(self, category, student,
272            previous_session=None, previous_level=None, combi=[]):
273        """Create Payment object and set the payment data of a student for
274        the payment category specified.
275
276        """
277        details = {}
278        p_item = u''
279        amount = 0.0
280        error = u''
281        if previous_session:
282            if previous_session < student['studycourse'].entry_session:
283                return _('The previous session must not fall below '
284                         'your entry session.'), None
285            if category == 'schoolfee':
286                # School fee is always paid for the following session
287                if previous_session > student['studycourse'].current_session:
288                    return _('This is not a previous session.'), None
289            else:
290                if previous_session > student['studycourse'].current_session - 1:
291                    return _('This is not a previous session.'), None
292            p_session = previous_session
293            p_level = previous_level
294            p_current = False
295        else:
296            p_session = student['studycourse'].current_session
297            p_level = student['studycourse'].current_level
298            p_current = True
299        academic_session = self._getSessionConfiguration(p_session)
300        if academic_session == None:
301            return _(u'Session configuration object is not available.'), None
302        # Determine fee.
303        if category == 'transfer':
304            amount = academic_session.transfer_fee
305        elif category == 'transcript_local':
306            amount = academic_session.transcript_fee_local
307        elif category == 'transcript_inter':
308            amount = academic_session.transcript_fee_inter
309        elif category == 'bed_allocation':
310            acco_details = self.getAccommodationDetails(student)
311            p_session = acco_details['booking_session']
312            p_item = acco_details['bt']
313            amount = academic_session.booking_fee
314        elif category == 'restitution':
315            if student.current_session != 2016 \
316                or student.current_mode not in ('ug_ft', 'dp_ft') \
317                or student.is_fresh:
318                return _(u'Restitution fee payment not required.'), None
319            amount = academic_session.restitution_fee
320        elif category == 'hostel_maintenance':
321            amount = 0.0
322            booking_session = grok.getSite()['hostels'].accommodation_session
323            bedticket = student['accommodation'].get(str(booking_session), None)
324            if bedticket is not None and bedticket.bed is not None:
325                p_session = booking_session
326                p_item = bedticket.display_coordinates
327                if bedticket.bed.__parent__.maint_fee > 0:
328                    amount = bedticket.bed.__parent__.maint_fee
329                else:
330                    # fallback
331                    amount = academic_session.maint_fee
332            else:
333                return _(u'No bed allocated.'), None
334        elif student.current_mode == 'found' and category not in (
335            'schoolfee', 'clearance', 'late_registration'):
336            return _('Not allowed.'), None
337        elif category.startswith('clearance'):
338            if student.state not in (ADMITTED, CLEARANCE, REQUESTED, CLEARED):
339                return _(u'Acceptance Fee payments not allowed.'), None
340            if student.current_mode in (
341                'ug_ft', 'ug_pt', 'de_ft', 'de_pt',
342                'transfer', 'mug_ft', 'mde_ft') \
343                and category != 'clearance_incl':
344                    return _("Additional fees must be included."), None
345            if student.current_mode == 'ijmbe':
346                amount = academic_session.clearance_fee_ijmbe
347            elif student.current_mode == 'bridge':
348                amount = academic_session.clearance_fee_bridge
349            elif student.current_mode == 'dp_ft':
350                amount = academic_session.clearance_fee_dp
351            elif student.faccode == 'FP':
352                amount = academic_session.clearance_fee_fp
353            elif student.current_mode in ('ug_pt', 'de_pt', 'ug_dsh', 'de_dsh'):
354                amount = academic_session.clearance_fee_ug_pt
355            elif student.current_mode == 'special_pg_pt':
356                amount = academic_session.clearance_fee_pg_pt
357            elif student.faccode == 'FCS':
358                # Students in clinical medical sciences pay the medical
359                # acceptance fee
360                amount = academic_session.clearance_fee_med
361            elif student.current_mode == 'special_pg_ft':
362                if category != 'clearance':
363                    return _("No additional fees required."), None
364                amount = academic_session.clearance_fee_pg
365            else:
366                amount = academic_session.clearance_fee
367            p_item = student['studycourse'].certificate.code
368            if amount in (0.0, None):
369                return _(u'Amount could not be determined.'), None
370            # Add Matric Gown Fee and Lapel Fee
371            if category == 'clearance_incl':
372                amount += gateway_net_amt(academic_session.matric_gown_fee) + \
373                    gateway_net_amt(academic_session.lapel_fee)
374        elif category == 'late_registration':
375            if student.is_postgrad:
376                amount = academic_session.late_pg_registration_fee
377            else:
378                amount = academic_session.late_registration_fee
379        elif category == 'ict':
380            if student.is_fresh:
381                amount = 2200
382            else:
383                amount = 1200
384        elif category.startswith('schoolfee'):
385            try:
386                certificate = student['studycourse'].certificate
387                p_item = certificate.code
388            except (AttributeError, TypeError):
389                return _('Study course data are incomplete.'), None
390            if student.is_postgrad and category != 'schoolfee':
391                return _("No additional fees required."), None
392            if not previous_session and student.current_mode in (
393                'ug_ft', 'ug_pt', 'de_ft', 'de_pt',
394                'transfer', 'mug_ft', 'mde_ft') \
395                and not category in (
396                'schoolfee_incl', 'schoolfee_1', 'schoolfee_2'):
397                    return _("You must choose a payment which includes "
398                             "additional fees."), None
399            if category in ('schoolfee_1', 'schoolfee_2'):
400                if student.current_mode == 'ug_pt':
401                    return _("Part-time students are not allowed "
402                             "to pay by instalments."), None
403                if student.entry_session < 2015:
404                    return _("You are not allowed "
405                             "to pay by instalments."), None
406            # We determine the base amount first
407            if student.entry_session < 2015:
408                amount = getattr(certificate, 'school_fee_3', 0.0)
409            elif student.entry_session < 2021:
410                amount = getattr(certificate, 'school_fee_2', 0.0)
411            else:
412                amount = getattr(certificate, 'school_fee_1', 0.0)
413            if previous_session:
414                # Students can pay for previous sessions in all
415                # workflow states.  Fresh students are excluded by the
416                # update method of the PreviousPaymentAddFormPage.
417                pass
418            elif student.state == CLEARED:
419                # Cut school fee by 50%
420                if category in ('schoolfee_1', 'schoolfee_2') and amount:
421                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
422            elif student.state == RETURNING and category != 'schoolfee_2':
423                if not student.father_name:
424                    return _("Personal data form is not properly filled."), None
425                # In case of returning school fee payment the payment session
426                # and level contain the values of the session the student
427                # has paid for.
428                p_session, p_level = self.getReturningData(student)
429                try:
430                    academic_session = grok.getSite()[
431                        'configuration'][str(p_session)]
432                except KeyError:
433                    return _(u'Session configuration object is not available.'), None
434                # Cut school fee by 50%
435                if category == 'schoolfee_1' and amount:
436                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
437            elif category == 'schoolfee_2' and 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                if student.entry_session >= 2021 \
456                    and student.current_mode == 'ug_ft':
457                    amount += gateway_net_amt(academic_session.lms_sund_fee)
458            # Add non-indigenous fee and session specific penalty fees
459            if student.is_postgrad:
460                amount += academic_session.penalty_pg
461                if student.lga and not student.lga.startswith('edo'):
462                    amount += 20000.0
463            else:
464                amount += academic_session.penalty_ug
465        #elif category == ('fac_dep'):
466        #    if student.faccode in ('FAT', 'FED', 'FLW', 'FMS', 'FSS'):
467        #        amount = 4200.0
468        #    elif student.faccode in ('FAG', 'FBM', 'FCS',
469        #                             'FES', 'FET', 'FLS', 'FPS'):
470        #        amount = 5200.0
471        #    elif student.faccode == 'FAG' and student.current_level == 400:
472        #        amount = 10200.0
473        #    elif student.depcode == 'VTE':
474        #        amount = 5200.0
475        #    if student.entry_session >= 2019:
476        #        amount += gateway_net_amt(academic_session.ict_fee)
477        elif category == 'sports_library': # temporarily in 2020
478            if student.is_postgrad:
479                amount = academic_session.sports_fee + gateway_net_amt(
480                    academic_session.library_pg_fee)
481            else:
482                amount = academic_session.sports_fee + gateway_net_amt(
483                    academic_session.library_fee)
484        elif not student.is_postgrad:
485            fee_name = category + '_fee'
486            amount = getattr(academic_session, fee_name, 0.0)
487        if amount in (0.0, None):
488            return _(u'Amount could not be determined.'), None
489        # Create ticket.
490        for key in student['payments'].keys():
491            ticket = student['payments'][key]
492            if ticket.p_state == 'paid' and\
493               ticket.p_category == category and \
494               not ticket.p_category.startswith('transcript') and \
495               ticket.p_item == p_item and \
496               ticket.p_session == p_session:
497                  return _('This type of payment has already been made.'), None
498            # Additional condition in AAUE
499            if category in ('schoolfee', 'schoolfee_incl', 'schoolfee_1'):
500                if ticket.p_state == 'paid' and \
501                   ticket.p_category in ('schoolfee',
502                                         'schoolfee_incl',
503                                         'schoolfee_1') and \
504                   ticket.p_item == p_item and \
505                   ticket.p_session == p_session:
506                      return _(
507                          'Another school fee payment for this '
508                          'session has already been made.'), None
509
510        if self._isPaymentDisabled(p_session, category, student):
511            return _('This category of payments has been disabled.'), None
512        payment = createObject(u'waeup.StudentOnlinePayment')
513        timestamp = ("%d" % int(time()*10000))[1:]
514        payment.p_id = "p%s" % timestamp
515        payment.p_category = category
516        payment.p_item = p_item
517        payment.p_session = p_session
518        payment.p_level = p_level
519        payment.p_current = p_current
520        payment.amount_auth = amount
521        return None, payment
522
523    def _admissionText(self, student, portal_language):
524        inst_name = grok.getSite()['configuration'].name
525        entry_session = student['studycourse'].entry_session
526        entry_session = academic_sessions_vocab.getTerm(entry_session).title
527        text = trans(_(
528            'This is to inform you that you have been offered provisional'
529            ' admission into ${a} for the ${b} academic session as follows:',
530            mapping = {'a': inst_name, 'b': entry_session}),
531            portal_language)
532        return text
533
534    def warnCreditsOOR(self, studylevel, course=None):
535        studycourse = studylevel.__parent__
536        certificate = getattr(studycourse,'certificate', None)
537        current_level = studycourse.current_level
538        if None in (current_level, certificate):
539            return
540        end_level = certificate.end_level
541        if current_level >= end_level:
542            limit = 52
543        else:
544            limit = 48
545        if course and studylevel.total_credits + course.credits > limit:
546            return  _('Maximum credits exceeded.')
547        elif studylevel.total_credits > limit:
548            return _('Maximum credits exceeded.')
549        return
550
551    def getBedCoordinates(self, bedticket):
552        """Return descriptive bed coordinates.
553        This method can be used to customize the `display_coordinates`
554        property method in order to  display a
555        customary description of the bed space.
556        """
557        bc = bedticket.bed_coordinates.split(',')
558        if len(bc) == 4:
559            return bc[0]
560        return bedticket.bed_coordinates
561
562    def getAccommodationDetails(self, student):
563        """Determine the accommodation data of a student.
564        """
565        d = {}
566        d['error'] = u''
567        hostels = grok.getSite()['hostels']
568        d['booking_session'] = hostels.accommodation_session
569        d['allowed_states'] = hostels.accommodation_states
570        d['startdate'] = hostels.startdate
571        d['enddate'] = hostels.enddate
572        d['expired'] = hostels.expired
573        # Determine bed type
574        bt = 'all'
575        if student.sex == 'f':
576            sex = 'female'
577        else:
578            sex = 'male'
579        special_handling = 'regular'
580        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
581        return d
582
583    def checkAccommodationRequirements(self, student, acc_details):
584        msg = super(CustomStudentsUtils, self).checkAccommodationRequirements(
585            student, acc_details)
586        if msg:
587            return msg
588        if student.current_mode not in ('ug_ft', 'de_ft', 'mug_ft', 'mde_ft'):
589            return _('You are not eligible to book accommodation.')
590        return
591
592    # AAUE prefix
593    STUDENT_ID_PREFIX = u'E'
594
595    STUDENT_EXPORTER_NAMES = (
596            'students',
597            'studentstudycourses',
598            'studentstudycourses_1',
599            'studentstudylevels',
600            #'studentstudylevels_1',
601            'coursetickets',
602            #'coursetickets_1',
603            'studentpayments',
604            'bedtickets',
605            'unpaidpayments',
606            'sfpaymentsoverview',
607            'studylevelsoverview',
608            'combocard',
609            'bursary',
610            'levelreportdata',
611            'outstandingcourses',
612            'sessionpaymentsoverview',
613            'accommodationpayments',
614            'transcriptdata',
615            'trimmedpayments',
616            'trimmed',
617            'outstandingcourses_2'
618            )
619
620    # Maximum size of upload files in kB
621    MAX_KB = 500
Note: See TracBrowser for help on using the repository browser.