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

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

Implement OutstandingCourses2Exporter (ticket 699)

  • Property svn:keywords set to Id
File size: 27.9 KB
Line 
1## $Id: utils.py 16859 2022-03-04 21:27:24Z 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            amount = academic_session.booking_fee
311        elif category == 'restitution':
312            if student.current_session != 2016 \
313                or student.current_mode not in ('ug_ft', 'dp_ft') \
314                or student.is_fresh:
315                return _(u'Restitution fee payment not required.'), None
316            amount = academic_session.restitution_fee
317        elif category == 'hostel_maintenance':
318            amount = 0.0
319            bedticket = student['accommodation'].get(
320                str(student.current_session), None)
321            if bedticket is not None and bedticket.bed is not None:
322                p_item = bedticket.display_coordinates
323                if bedticket.bed.__parent__.maint_fee > 0:
324                    amount = bedticket.bed.__parent__.maint_fee
325                else:
326                    # fallback
327                    amount = academic_session.maint_fee
328            else:
329                return _(u'No bed allocated.'), None
330        elif student.current_mode == 'found' and category not in (
331            'schoolfee', 'clearance', 'late_registration'):
332            return _('Not allowed.'), None
333        elif category.startswith('clearance'):
334            if student.state not in (ADMITTED, CLEARANCE, REQUESTED, CLEARED):
335                return _(u'Acceptance Fee payments not allowed.'), None
336            if student.current_mode in (
337                'ug_ft', 'ug_pt', 'de_ft', 'de_pt',
338                'transfer', 'mug_ft', 'mde_ft') \
339                and category != 'clearance_incl':
340                    return _("Additional fees must be included."), None
341            if student.current_mode == 'ijmbe':
342                amount = academic_session.clearance_fee_ijmbe
343            elif student.current_mode == 'bridge':
344                amount = academic_session.clearance_fee_bridge
345            elif student.current_mode == 'dp_ft':
346                amount = academic_session.clearance_fee_dp
347            elif student.faccode == 'FP':
348                amount = academic_session.clearance_fee_fp
349            elif student.current_mode in ('ug_pt', 'de_pt', 'ug_dsh', 'de_dsh'):
350                amount = academic_session.clearance_fee_ug_pt
351            elif student.current_mode == 'special_pg_pt':
352                amount = academic_session.clearance_fee_pg_pt
353            elif student.faccode == 'FCS':
354                # Students in clinical medical sciences pay the medical
355                # acceptance fee
356                amount = academic_session.clearance_fee_med
357            elif student.current_mode == 'special_pg_ft':
358                if category != 'clearance':
359                    return _("No additional fees required."), None
360                amount = academic_session.clearance_fee_pg
361            else:
362                amount = academic_session.clearance_fee
363            p_item = student['studycourse'].certificate.code
364            if amount in (0.0, None):
365                return _(u'Amount could not be determined.'), None
366            # Add Matric Gown Fee and Lapel Fee
367            if category == 'clearance_incl':
368                amount += gateway_net_amt(academic_session.matric_gown_fee) + \
369                    gateway_net_amt(academic_session.lapel_fee)
370        elif category == 'late_registration':
371            if student.is_postgrad:
372                amount = academic_session.late_pg_registration_fee
373            else:
374                amount = academic_session.late_registration_fee
375        elif category == 'ict':
376            if student.is_fresh:
377                amount = 2200
378            else:
379                amount = 1200
380        elif category.startswith('schoolfee'):
381            try:
382                certificate = student['studycourse'].certificate
383                p_item = certificate.code
384            except (AttributeError, TypeError):
385                return _('Study course data are incomplete.'), None
386            if student.is_postgrad and category != 'schoolfee':
387                return _("No additional fees required."), None
388            if not previous_session and student.current_mode in (
389                'ug_ft', 'ug_pt', 'de_ft', 'de_pt',
390                'transfer', 'mug_ft', 'mde_ft') \
391                and not category in (
392                'schoolfee_incl', 'schoolfee_1', 'schoolfee_2'):
393                    return _("You must choose a payment which includes "
394                             "additional fees."), None
395            if category in ('schoolfee_1', 'schoolfee_2'):
396                if student.current_mode == 'ug_pt':
397                    return _("Part-time students are not allowed "
398                             "to pay by instalments."), None
399                if student.entry_session < 2015:
400                    return _("You are not allowed "
401                             "to pay by instalments."), None
402            if previous_session:
403                # Students can pay for previous sessions in all
404                # workflow states.  Fresh students are excluded by the
405                # update method of the PreviousPaymentAddFormPage.
406                if previous_level == 100:
407                    amount = getattr(certificate, 'school_fee_1', 0.0)
408                else:
409                    if student.entry_session in (2015, 2016):
410                        amount = getattr(certificate, 'school_fee_2', 0.0)
411                    else:
412                        amount = getattr(certificate, 'school_fee_3', 0.0)
413            elif student.state == CLEARED and category != 'schoolfee_2':
414                amount = getattr(certificate, 'school_fee_1', 0.0)
415                # Cut school fee by 50%
416                if category == 'schoolfee_1' and amount:
417                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
418            elif student.is_fresh and category == 'schoolfee_2':
419                amount = getattr(certificate, 'school_fee_1', 0.0)
420                # Cut school fee by 50%
421                if amount:
422                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
423            elif student.state == RETURNING and category != 'schoolfee_2':
424                if not student.father_name:
425                    return _("Personal data form is not properly filled."), None
426                # In case of returning school fee payment the payment session
427                # and level contain the values of the session the student
428                # has paid for.
429                p_session, p_level = self.getReturningData(student)
430                try:
431                    academic_session = grok.getSite()[
432                        'configuration'][str(p_session)]
433                except KeyError:
434                    return _(u'Session configuration object is not available.'), None
435                if student.entry_session >= 2015:
436                    amount = getattr(certificate, 'school_fee_2', 0.0)
437                else:
438                    amount = getattr(certificate, 'school_fee_3', 0.0)
439                # Cut school fee by 50%
440                if category == 'schoolfee_1' and amount:
441                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
442            elif category == 'schoolfee_2':
443                amount = getattr(certificate, 'school_fee_2', 0.0)
444                # Cut school fee by 50%
445                if amount:
446                    amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
447            else:
448                return _('Wrong state.'), None
449            if amount in (0.0, None):
450                return _(u'Amount could not be determined.'), None
451            # Add Student Union Fee, Student Id Card Fee, Sports Dev. Fee,
452            # Library Dev. Fee and Welfare Assurance
453            if category in ('schoolfee_incl', 'schoolfee_1') \
454                and student.current_mode != 'ijmbe':
455                amount += gateway_net_amt(academic_session.welfare_fee) + \
456                    gateway_net_amt(academic_session.union_fee)
457                if student.entry_session >= 2018 and student.is_fresh:
458                    amount += gateway_net_amt(academic_session.sports_fee)
459                    if student.is_postgrad:
460                        amount += gateway_net_amt(academic_session.library_pg_fee)
461                    else:
462                        amount += gateway_net_amt(academic_session.library_fee)
463            # Add non-indigenous fee and session specific penalty fees
464            if student.is_postgrad:
465                amount += academic_session.penalty_pg
466                if student.lga and not student.lga.startswith('edo'):
467                    amount += 20000.0
468            else:
469                amount += academic_session.penalty_ug
470        #elif category == ('fac_dep'):
471        #    if student.faccode in ('FAT', 'FED', 'FLW', 'FMS', 'FSS'):
472        #        amount = 4200.0
473        #    elif student.faccode in ('FAG', 'FBM', 'FCS',
474        #                             'FES', 'FET', 'FLS', 'FPS'):
475        #        amount = 5200.0
476        #    elif student.faccode == 'FAG' and student.current_level == 400:
477        #        amount = 10200.0
478        #    elif student.depcode == 'VTE':
479        #        amount = 5200.0
480        #    if student.entry_session >= 2019:
481        #        amount += gateway_net_amt(academic_session.ict_fee)
482        elif category == 'sports_library': # temporarily in 2020
483            if student.is_postgrad:
484                amount = academic_session.sports_fee + gateway_net_amt(
485                    academic_session.library_pg_fee)
486            else:
487                amount = academic_session.sports_fee + gateway_net_amt(
488                    academic_session.library_fee)
489        elif not student.is_postgrad:
490            fee_name = category + '_fee'
491            amount = getattr(academic_session, fee_name, 0.0)
492        if amount in (0.0, None):
493            return _(u'Amount could not be determined.'), None
494        # Create ticket.
495        for key in student['payments'].keys():
496            ticket = student['payments'][key]
497            if ticket.p_state == 'paid' and\
498               ticket.p_category == category and \
499               not ticket.p_category.startswith('transcript') and \
500               ticket.p_item == p_item and \
501               ticket.p_session == p_session:
502                  return _('This type of payment has already been made.'), None
503            # Additional condition in AAUE
504            if category in ('schoolfee', 'schoolfee_incl', 'schoolfee_1'):
505                if ticket.p_state == 'paid' and \
506                   ticket.p_category in ('schoolfee',
507                                         'schoolfee_incl',
508                                         'schoolfee_1') and \
509                   ticket.p_item == p_item and \
510                   ticket.p_session == p_session:
511                      return _(
512                          'Another school fee payment for this '
513                          'session has already been made.'), None
514
515        if self._isPaymentDisabled(p_session, category, student):
516            return _('This category of payments has been disabled.'), None
517        payment = createObject(u'waeup.StudentOnlinePayment')
518        timestamp = ("%d" % int(time()*10000))[1:]
519        payment.p_id = "p%s" % timestamp
520        payment.p_category = category
521        payment.p_item = p_item
522        payment.p_session = p_session
523        payment.p_level = p_level
524        payment.p_current = p_current
525        payment.amount_auth = amount
526        return None, payment
527
528    def _admissionText(self, student, portal_language):
529        inst_name = grok.getSite()['configuration'].name
530        entry_session = student['studycourse'].entry_session
531        entry_session = academic_sessions_vocab.getTerm(entry_session).title
532        text = trans(_(
533            'This is to inform you that you have been offered provisional'
534            ' admission into ${a} for the ${b} academic session as follows:',
535            mapping = {'a': inst_name, 'b': entry_session}),
536            portal_language)
537        return text
538
539    def warnCreditsOOR(self, studylevel, course=None):
540        studycourse = studylevel.__parent__
541        certificate = getattr(studycourse,'certificate', None)
542        current_level = studycourse.current_level
543        if None in (current_level, certificate):
544            return
545        end_level = certificate.end_level
546        if current_level >= end_level:
547            limit = 52
548        else:
549            limit = 48
550        if course and studylevel.total_credits + course.credits > limit:
551            return  _('Maximum credits exceeded.')
552        elif studylevel.total_credits > limit:
553            return _('Maximum credits exceeded.')
554        return
555
556    def getBedCoordinates(self, bedticket):
557        """Return descriptive bed coordinates.
558        This method can be used to customize the `display_coordinates`
559        property method in order to  display a
560        customary description of the bed space.
561        """
562        bc = bedticket.bed_coordinates.split(',')
563        if len(bc) == 4:
564            return bc[0]
565        return bedticket.bed_coordinates
566
567    def getAccommodationDetails(self, student):
568        """Determine the accommodation data of a student.
569        """
570        d = {}
571        d['error'] = u''
572        hostels = grok.getSite()['hostels']
573        d['booking_session'] = hostels.accommodation_session
574        d['allowed_states'] = hostels.accommodation_states
575        d['startdate'] = hostels.startdate
576        d['enddate'] = hostels.enddate
577        d['expired'] = hostels.expired
578        # Determine bed type
579        bt = 'all'
580        if student.sex == 'f':
581            sex = 'female'
582        else:
583            sex = 'male'
584        special_handling = 'regular'
585        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
586        return d
587
588    def checkAccommodationRequirements(self, student, acc_details):
589        msg = super(CustomStudentsUtils, self).checkAccommodationRequirements(
590            student, acc_details)
591        if msg:
592            return msg
593        if student.current_mode not in ('ug_ft', 'de_ft', 'mug_ft', 'mde_ft'):
594            return _('You are not eligible to book accommodation.')
595        return
596
597    # AAUE prefix
598    STUDENT_ID_PREFIX = u'E'
599
600    STUDENT_EXPORTER_NAMES = (
601            'students',
602            'studentstudycourses',
603            'studentstudylevels',
604            'coursetickets',
605            'studentpayments',
606            'bedtickets',
607            'unpaidpayments',
608            'sfpaymentsoverview',
609            'studylevelsoverview',
610            'combocard',
611            'bursary',
612            'levelreportdata',
613            'outstandingcourses',
614            'sessionpaymentsoverview',
615            'accommodationpayments',
616            'transcriptdata',
617            'trimmedpayments',
618            'trimmed',
619            'outstandingcourses_2'
620            )
621
622    # Maximum size of upload files in kB
623    MAX_KB = 500
Note: See TracBrowser for help on using the repository browser.