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

Last change on this file since 13800 was 13798, checked in by Henrik Bettermann, 9 years ago

Change flash message.

  • Property svn:keywords set to Id
File size: 16.5 KB
RevLine 
[7419]1## $Id: utils.py 13798 2016-04-04 09:05:53Z 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##
[7151]18import grok
[8600]19from time import time
20from zope.component import createObject
[10922]21from waeup.kofa.interfaces import (
[13594]22    ADMITTED, CLEARANCE, REQUESTED, CLEARED, RETURNING, PAID,
23    academic_sessions_vocab)
[8823]24from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
[8247]25from waeup.kofa.accesscodes import create_accesscode
[10922]26from waeup.kofa.students.utils import trans
[13720]27from waeup.aaue.interswitch.browser import gateway_net_amt, GATEWAY_AMT
[8444]28from waeup.aaue.interfaces import MessageFactory as _
[6902]29
[8823]30class CustomStudentsUtils(NigeriaStudentsUtils):
[7151]31    """A collection of customized methods.
32
33    """
34
[13348]35    PORTRAIT_CHANGE_STATES = (ADMITTED, RETURNING)
36
[10641]37    gpa_boundaries = ((1, 'FRNS'),
38                      (1.5, 'Pass'),
39                      (2.4, '3rd Class Honours'),
40                      (3.5, '2nd Class Honours Lower Division'),
41                      (4.5, '2nd Class Honours Upper Division'),
42                      (5, '1st Class Honours'))
43
[13359]44    def increaseMatricInteger(self, student):
45        """Increase counter for matric numbers.
46        This counter can be a centrally stored attribute or an attribute of
47        faculties, departments or certificates. In the base package the counter
48        is as an attribute of the site configuration container.
49        """
50        if student.current_mode in ('ug_pt', 'de_pt'):
51            grok.getSite()['configuration'].next_matric_integer += 1
52            return
[13609]53        elif student.is_postgrad:
54            grok.getSite()['configuration'].next_matric_integer_3 += 1
55            return
[13793]56        elif student.current_mode in ('dp_ft',):
57            grok.getSite()['configuration'].next_matric_integer_4 += 1
58            return
[13359]59        grok.getSite()['configuration'].next_matric_integer_2 += 1
60        return
61
[13749]62    def _concessionalPaymentMade(self, student):
63        if len(student['payments']):
64            for ticket in student['payments'].values():
65                if ticket.p_state == 'paid' and \
66                    ticket.p_category == 'concessional':
67                    return True
68        return False
69
[11596]70    def constructMatricNumber(self, student):
[11593]71        faccode = student.faccode
72        depcode = student.depcode
[13609]73        certcode = student.certcode
[13664]74        degree = getattr(
75            getattr(student.get('studycourse', None), 'certificate', None),
76                'degree', None)
[11593]77        year = unicode(student.entry_session)[2:]
[13359]78        if not student.state in (PAID, ) or not student.is_fresh or \
79            student.current_mode == 'found':
80            return _('Matriculation number cannot be set.'), None
[13755]81        #if student.current_mode not in ('mug_ft', 'mde_ft') and \
82        #    not self._concessionalPaymentMade(student):
83        #    return _('Matriculation number cannot be set.'), None
[13571]84        if student.is_postgrad:
[13609]85            next_integer = grok.getSite()['configuration'].next_matric_integer_3
[13664]86            if not degree or next_integer == 0:
[13609]87                return _('Matriculation number cannot be set.'), None
88            return None, "AAU/SPS/%s/%s/%s/%s/%05d" % (
[13664]89                faccode, depcode, year, degree, next_integer)
[13359]90        if student.current_mode in ('ug_pt', 'de_pt'):
91            next_integer = grok.getSite()['configuration'].next_matric_integer
92            if next_integer == 0:
93                return _('Matriculation number cannot be set.'), None
[12975]94            return None, "PTP/%s/%s/%s/%05d" % (
95                faccode, depcode, year, next_integer)
[13793]96        if student.current_mode in ('dp_ft',):
97            next_integer = grok.getSite()['configuration'].next_matric_integer_4
98            if next_integer == 0:
99                return _('Matriculation number cannot be set.'), None
100            return None, "IOE/DIP/%s/%05d" % (year, next_integer)
[13359]101        next_integer = grok.getSite()['configuration'].next_matric_integer_2
102        if next_integer == 0:
103            return _('Matriculation number cannot be set.'), None
104        if student.faccode in ('FBM', 'FCS'):
105            return None, "CMS/%s/%s/%s/%05d" % (
106                faccode, depcode, year, next_integer)
107        return None, "%s/%s/%s/%05d" % (faccode, depcode, year, next_integer)
[12975]108
[8270]109    def getReturningData(self, student):
110        """ This method defines what happens after school fee payment
[8319]111        of returning students depending on the student's senate verdict.
[8270]112        """
[8319]113        prev_level = student['studycourse'].current_level
114        cur_verdict = student['studycourse'].current_verdict
115        if cur_verdict in ('A','B','L','M','N','Z',):
116            # Successful student
117            new_level = divmod(int(prev_level),100)[0]*100 + 100
118        elif cur_verdict == 'C':
119            # Student on probation
120            new_level = int(prev_level) + 10
121        else:
122            # Student is somehow in an undefined state.
123            # Level has to be set manually.
124            new_level = prev_level
[8270]125        new_session = student['studycourse'].current_session + 1
126        return new_session, new_level
127
[13454]128    def _isPaymentDisabled(self, p_session, category, student):
129        academic_session = self._getSessionConfiguration(p_session)
[13794]130        if category.startswith('schoolfee') and \
[13454]131            'sf_all' in academic_session.payment_disabled:
132            return True
[13794]133        if category.startswith('clearance') and \
134            'cl_regular' in academic_session.payment_disabled and \
135            student.current_mode in ('ug_ft', 'de_ft', 'mug_ft', 'mde_ft'):
136            return True
[13454]137        if category == 'hostel_maintenance' and \
138            'maint_all' in academic_session.payment_disabled:
139            return True
140        return False
141
[9154]142    def setPaymentDetails(self, category, student,
143            previous_session=None, previous_level=None):
[8600]144        """Create Payment object and set the payment data of a student for
145        the payment category specified.
146
147        """
[8306]148        details = {}
[8600]149        p_item = u''
150        amount = 0.0
151        error = u''
[9154]152        if previous_session:
153            return _('Previous session payment not yet implemented.'), None
[8600]154        p_session = student['studycourse'].current_session
155        p_level = student['studycourse'].current_level
[9154]156        p_current = True
[9527]157        academic_session = self._getSessionConfiguration(p_session)
158        if academic_session == None:
[8600]159            return _(u'Session configuration object is not available.'), None
[8677]160        # Determine fee.
[7151]161        if category == 'transfer':
[8600]162            amount = academic_session.transfer_fee
[10467]163        elif category == 'transcript':
164            amount = academic_session.transcript_fee
[7151]165        elif category == 'bed_allocation':
[8600]166            amount = academic_session.booking_fee
[7151]167        elif category == 'hostel_maintenance':
[13418]168            amount = 0.0
169            bedticket = student['accommodation'].get(
170                str(student.current_session), None)
[13502]171            if bedticket is not None and bedticket.bed is not None:
[13474]172                p_item = bedticket.display_coordinates
[13418]173                if bedticket.bed.__parent__.maint_fee > 0:
174                    amount = bedticket.bed.__parent__.maint_fee
175                else:
176                    # fallback
177                    amount = academic_session.maint_fee
178            else:
[13506]179                return _(u'No bed allocated.'), None
[13374]180        elif category == 'welfare':
181            amount = academic_session.welfare_fee
182        elif category == 'union':
183            amount = academic_session.union_fee
184        elif category == 'lapel':
185            amount = academic_session.lapel_fee
186        elif category == 'matric_gown':
187            amount = academic_session.matric_gown_fee
188        elif category == 'concessional':
[13464]189            amount = academic_session.concessional_fee
[13636]190        elif student.current_mode == 'found' and category not in (
191            'schoolfee', 'clearance', 'late_registration'):
192            return _('Not allowed.'), None
[13400]193        elif category.startswith('clearance'):
[13594]194            if student.state not in (ADMITTED, CLEARANCE, REQUESTED, CLEARED):
195                return _(u'Acceptance Fee payments not allowed.'), None
[11653]196            if student.faccode == 'FP':
197                amount = academic_session.clearance_fee_fp
[13377]198            elif student.current_mode.endswith('_pt'):
[13678]199                if student.is_postgrad:
200                    amount = academic_session.clearance_fee_pg_pt
201                else:
202                    amount = academic_session.clearance_fee_ug_pt
[13466]203            elif student.faccode == 'FCS':
204                # Students in clinical medical sciences pay the medical
205                # acceptance fee
[13377]206                amount = academic_session.clearance_fee_med
[13678]207            elif student.is_postgrad:  # and not part-time
[13526]208                amount = academic_session.clearance_fee_pg
[11653]209            else:
210                amount = academic_session.clearance_fee
[8753]211            p_item = student['studycourse'].certificate.code
[13689]212            if amount in (0.0, None):
213                return _(u'Amount could not be determined.'), None
[13400]214            # Add Matric Gown Fee and Lapel Fee
[13689]215            if category == 'clearance_incl':
[13414]216                amount += gateway_net_amt(academic_session.matric_gown_fee) + \
217                    gateway_net_amt(academic_session.lapel_fee)
[11004]218        elif category == 'late_registration':
[13035]219            amount = academic_session.late_registration_fee
[13400]220        elif category.startswith('schoolfee'):
[8600]221            try:
[8753]222                certificate = student['studycourse'].certificate
223                p_item = certificate.code
[8600]224            except (AttributeError, TypeError):
225                return _('Study course data are incomplete.'), None
[13780]226            if category in ('schoolfee_1', 'schoolfee_2'):
227                if student.current_mode == 'ug_pt':
228                    return _("Part-time students are not allowed "
229                             "to pay by instalments."), None
230                if category == 'schoolfee_1' and student.state != CLEARED:
231                    return _("Wrong state. Only students in state 'cleared' "
232                             "are allowed to pay by instalments."), None
[13512]233            if student.state == CLEARED or category == 'schoolfee_2':
[13374]234                if student.is_foreigner:
235                    amount = getattr(certificate, 'school_fee_3', 0.0)
[10930]236                else:
[13374]237                    amount = getattr(certificate, 'school_fee_1', 0.0)
[13512]238                # Cut school fee by 50%
239                if category in ('schoolfee_1', 'schoolfee_2'):
[13720]240                    if amount:
241                        amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
[13374]242            elif student.state == RETURNING:
[13526]243                if student.is_postgrad and category == 'schoolfee_incl':
244                    return _("No additional fees required."), None
[13482]245                if not student.father_name:
246                    return _("Personal data form is not properly filled."), None
[13374]247                # In case of returning school fee payment the payment session
248                # and level contain the values of the session the student
249                # has paid for.
250                p_session, p_level = self.getReturningData(student)
[8961]251                try:
252                    academic_session = grok.getSite()[
253                        'configuration'][str(p_session)]
254                except KeyError:
255                    return _(u'Session configuration object is not available.'), None
[13374]256                if student.is_foreigner:
257                    amount = getattr(certificate, 'school_fee_4', 0.0)
258                else:
259                    amount = getattr(certificate, 'school_fee_2', 0.0)
[8600]260            else:
[8753]261                return _('Wrong state.'), None
[13417]262            if amount in (0.0, None):
263                return _(u'Amount could not be determined.'), None
[13400]264            # Add Student Union Fee and Welfare Assurance
[13512]265            if category in ('schoolfee_incl', 'schoolfee_1'):
[13414]266                amount += gateway_net_amt(academic_session.welfare_fee) + \
267                    gateway_net_amt(academic_session.union_fee)
[13534]268            # Add non-indigenous fee and session specific penalty fees
269            if student.is_postgrad:
270                amount += academic_session.penalty_pg
271                if not student.lga.startswith('edo'):
272                    amount += 20000.0
273            else:
274                amount += academic_session.penalty_ug
[8600]275        if amount in (0.0, None):
276            return _(u'Amount could not be determined.'), None
[8677]277        # Create ticket.
[8600]278        for key in student['payments'].keys():
279            ticket = student['payments'][key]
280            if ticket.p_state == 'paid' and\
281               ticket.p_category == category and \
282               ticket.p_item == p_item and \
283               ticket.p_session == p_session:
284                  return _('This type of payment has already been made.'), None
[13786]285            # Additional condition in AAUE
286            if category in ('schoolfee', 'schoolfee_incl', 'schoolfee_1'):
287                if ticket.p_state == 'paid' and \
288                   ticket.p_category in ('schoolfee',
289                                         'schoolfee_incl',
290                                         'schoolfee_1') and \
291                   ticket.p_item == p_item and \
292                   ticket.p_session == p_session:
293                      return _(
294                          'Another school fee payment for this '
295                          'session has already been made.'), None
296
[11455]297        if self._isPaymentDisabled(p_session, category, student):
[13798]298            return _('This category of payments has been disabled.'), None
[8712]299        payment = createObject(u'waeup.StudentOnlinePayment')
[8954]300        timestamp = ("%d" % int(time()*10000))[1:]
[8600]301        payment.p_id = "p%s" % timestamp
302        payment.p_category = category
303        payment.p_item = p_item
304        payment.p_session = p_session
305        payment.p_level = p_level
[9154]306        payment.p_current = p_current
[8600]307        payment.amount_auth = amount
308        return None, payment
[7621]309
[10922]310    def _admissionText(self, student, portal_language):
311        inst_name = grok.getSite()['configuration'].name
312        entry_session = student['studycourse'].entry_session
313        entry_session = academic_sessions_vocab.getTerm(entry_session).title
314        text = trans(_(
[10953]315            'This is to inform you that you have been offered provisional'
316            ' admission into ${a} for the ${b} academic session as follows:',
[10922]317            mapping = {'a': inst_name, 'b': entry_session}),
318            portal_language)
319        return text
320
[10051]321    def maxCredits(self, studylevel):
322        """Return maximum credits.
323
324        """
325        return 48
326
[13353]327    def getBedCoordinates(self, bedticket):
328        """Return descriptive bed coordinates.
329        This method can be used to customize the `display_coordinates`
330        property method in order to  display a
331        customary description of the bed space.
332        """
333        bc = bedticket.bed_coordinates.split(',')
334        if len(bc) == 4:
335            return bc[0]
336        return bedticket.bed_coordinates
337
[13415]338    def getAccommodationDetails(self, student):
339        """Determine the accommodation data of a student.
340        """
341        d = {}
342        d['error'] = u''
343        hostels = grok.getSite()['hostels']
344        d['booking_session'] = hostels.accommodation_session
345        d['allowed_states'] = hostels.accommodation_states
346        d['startdate'] = hostels.startdate
347        d['enddate'] = hostels.enddate
348        d['expired'] = hostels.expired
349        # Determine bed type
[13416]350        bt = 'all'
[13415]351        if student.sex == 'f':
352            sex = 'female'
353        else:
354            sex = 'male'
355        special_handling = 'regular'
356        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
357        return d
358
[13753]359    def checkAccommodationRequirements(self, student, acc_details):
360        super(CustomStudentsUtils, self).checkAccommodationRequirements(
361            student, acc_details)
362        if student.current_mode not in ('ug_ft', 'de_ft', 'mug_ft', 'mde_ft'):
363            return _('You are not eligible to book accommodation.')
364        return
365
[8444]366    # AAUE prefix
367    STUDENT_ID_PREFIX = u'E'
Note: See TracBrowser for help on using the repository browser.