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

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

ivama: please kindly update it because at extension year, 3 units taken is allowed.

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