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

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

Disable concessional fee requirement.

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