source: main/kofacustom.coewarri/trunk/src/kofacustom/coewarri/students/utils.py @ 17238

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

include ug_ft and de_ft to the nce_ft and nce_pt initially set for lsfp_penalty_fee 2020/2021 session

  • Property svn:keywords set to Id
File size: 9.8 KB
Line 
1## $Id: utils.py 16524 2021-07-01 08:31:33Z 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##
18from time import time
19from zope.component import createObject, getUtility
20from waeup.kofa.fees import FeeTable
21from waeup.kofa.interfaces import (IKofaUtils,
22    ADMITTED, CLEARED, RETURNING, PAID, REGISTERED, VALIDATED)
23from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
24from kofacustom.coewarri.interfaces import MessageFactory as _
25from kofacustom.coewarri.interswitch.browser import GATEWAY_AMT
26
27
28def local_nonlocal(student):
29    lga = getattr(student, 'lga')
30    if lga and lga.startswith('delta'):
31        return 'local'
32    else:
33        return 'non-local'
34
35PAYMENT_LEVELS = (100, 110, 200, 210, 300, 310, 400, 410, 500, 999)
36
37FEES_PARAMS = (
38        ('local', 'non-local'),
39        ('nce_ft', 'nce_pt', 'ug_ft', 'nce_we_pt'),
40        PAYMENT_LEVELS
41    )
42
43FEES_VALUES = (
44     ( # 100      110      200      210      300      310      400      410     500  999
45       (43200.0, 43200.0, 43200.0, 43200.0, 37200.0, 37200.0, 0.0, 0.0, 0.0, 0.0), # nce_ft
46       (55200.0, 55200.0, 49200.0, 49200.0, 53200.0, 53200.0, 49200.0, 49200.0, 0.0, 0.0), # nce_pt
47       (75700.0, 75700.0, 64700.0, 64700.0, 68700.0, 68700.0, 62700.0, 62700.0, 0.0, 0.0), # ug_ft
48       (33200.0, 33200.0, 28000.0, 28000.0, 32000.0, 32000.0, 28000.0, 28000.0, 0.0, 0.0), # nce_we_pt
49     ), # local
50     ( #
51       (55800.0, 55800.0, 55700.0, 55700.0, 49700.0, 49700.0, 0.0, 0.0, 0.0, 0.0), # nce_ft
52       (55200.0, 55200.0, 49200.0, 49200.0, 53200.0, 53200.0, 49200.0, 49200.0, 0.0, 0.0), # nce_pt
53       (85700.0, 85700.0, 74700.0, 74700.0, 78700.0, 78700.0, 72700.0, 72700.0, 0.0, 0.0), # ug_ft
54       (33200.0, 33200.0, 28000.0, 28000.0, 32000.0, 32000.0, 28000.0, 28000.0, 0.0, 0.0), # nce_we_pt
55     ), # non-local
56   )
57
58SCHOOL_FEES = FeeTable(FEES_PARAMS, FEES_VALUES)
59
60class CustomStudentsUtils(NigeriaStudentsUtils):
61    """A collection of customized methods.
62
63    """
64
65    def warnCreditsOOR(self, studylevel, course=None):
66        """Return message if credits are out of range.
67        """
68        if studylevel.student.current_mode == 'nce_ft':
69            limit = 56
70        elif studylevel.student.current_mode == 'ug_ft':
71            limit = 48
72            if studylevel.level == 400:
73                limit = 51
74        else:
75            limit = 50
76        if course and studylevel.total_credits + course.credits > limit:
77            return _('Maximum credits exceeded.')
78        elif studylevel.total_credits > limit:
79            return _('Maximum credits exceeded.')
80        return
81
82    def _isPaymentDisabled(self, p_session, category, student):
83        academic_session = self._getSessionConfiguration(p_session)
84        if category.startswith('schoolfee'):
85            if 'sf_all' in academic_session.payment_disabled:
86                return True
87            if student.current_mode == 'ug_ft' and \
88                'degree' in academic_session.payment_disabled:
89                return True
90        return False
91
92    def _lsfp_penalty_payment(self, student, p_session):
93        if p_session >= 2021:
94            return False
95        #if p_session == 2020 and student.current_mode not in ('nce_ft', 'nce_pt'):
96        #    return False
97        if student.current_mode not in ('ug_ft','de_ft', 'nce_ft', 'nce_pt'):
98            return False
99        if len(student['payments']):
100            for ticket in student['payments'].values():
101                if ticket.p_state == 'paid' and \
102                    ticket.p_category == 'lsfp_penalty' and \
103                    ticket.p_session == p_session:
104                    return False
105        return True
106
107    def setPaymentDetails(self, category, student,
108            previous_session=None, previous_level=None, combi=[]):
109        """Create a payment ticket and set the payment data of a
110        student for the payment category specified.
111        """
112        p_item = u''
113        amount = 0.0
114        if previous_session:
115            if previous_session < student['studycourse'].entry_session:
116                return _('The previous session must not fall below '
117                         'your entry session.'), None
118            if category == 'schoolfee':
119                # School fee is always paid for the following session
120                if previous_session > student['studycourse'].current_session:
121                    return _('This is not a previous session.'), None
122            else:
123                if previous_session > student['studycourse'].current_session - 1:
124                    return _('This is not a previous session.'), None
125            p_session = previous_session
126            p_level = previous_level
127            p_current = False
128        else:
129            p_session = student['studycourse'].current_session
130            p_level = student['studycourse'].current_level
131            p_current = True
132        academic_session = self._getSessionConfiguration(p_session)
133        if academic_session == None:
134            return _(u'Session configuration object is not available.'), None
135        # Determine fee.
136        if category.startswith('schoolfee'):
137            try:
138                certificate = student['studycourse'].certificate
139                p_item = certificate.code
140            except (AttributeError, TypeError):
141                return _('Study course data are incomplete.'), None
142            if student.state == RETURNING:
143                # Override p_session and p_level
144                p_session, p_level = self.getReturningData(student)
145                academic_session = self._getSessionConfiguration(p_session)
146                if academic_session == None:
147                    return _(u'Session configuration object '
148                              'is not available.'), None
149            penalty_set = getattr(academic_session, 'lsfp_penalty_fee')
150            if penalty_set and self._lsfp_penalty_payment(student, p_session):
151                return _('You have to pay late school fee payment penalty first.'), None
152            if p_level in PAYMENT_LEVELS:
153                amount = SCHOOL_FEES.get_fee(
154                    (
155                     local_nonlocal(student),
156                     student.current_mode,
157                     p_level)
158                    )
159                if student.entry_mode == 'de_ft' and p_level == 200:
160                    if student['studycourse'].entry_session >= 2020:
161                        amount += 15000
162                    elif student['studycourse'].entry_session >= 2019:
163                        amount += 10500
164            if amount and category in ('schoolfee_1', 'schoolfee_2'):
165                amount /= 2
166            if amount:
167                amount += GATEWAY_AMT
168        elif category == 'clearance':
169            try:
170                p_item = student['studycourse'].certificate.code
171            except (AttributeError, TypeError):
172                return _('Study course data are incomplete.'), None
173            if student.entry_mode in ('nce_we_pt', 'nce_pt'):
174                amount = academic_session.clearance_fee_3
175            elif student.entry_mode in ('ug_ft', 'de_ft'):
176                amount = academic_session.clearance_fee_2
177            else:
178                amount = academic_session.clearance_fee_1
179            if local_nonlocal(student) == 'non-local'  \
180                and student.entry_mode not in ('nce_we_pt', 'nce_pt'):
181                amount += 5000.0
182        elif category == 'bed_allocation':
183            p_item = self.getAccommodationDetails(student)['bt']
184            amount = academic_session.booking_fee
185        elif category == 'hostel_maintenance':
186            amount = 0.0
187            bedticket = student['accommodation'].get(
188                str(student.current_session), None)
189            if bedticket is not None and bedticket.bed is not None:
190                p_item = bedticket.bed_coordinates
191                if bedticket.bed.__parent__.maint_fee > 0:
192                    amount = bedticket.bed.__parent__.maint_fee
193                else:
194                    # fallback
195                    amount = academic_session.maint_fee
196            else:
197                return _(u'No bed allocated.'), None
198        else:
199            fee_name = category + '_fee'
200            amount = getattr(academic_session, fee_name, 0.0)
201        if category == 'lsfp_penalty' and student.state == RETURNING:
202            # Override p_session and p_level
203            p_session, p_level = self.getReturningData(student)
204        if amount in (0.0, None):
205            return _('Amount could not be determined.'), None
206        if self.samePaymentMade(student, category, p_item, p_session):
207            return _('This type of payment has already been made.'), None
208        if self._isPaymentDisabled(p_session, category, student):
209            return _('This category of payments has been disabled.'), None
210        payment = createObject(u'waeup.StudentOnlinePayment')
211        timestamp = ("%d" % int(time()*10000))[1:]
212        payment.p_id = "p%s" % timestamp
213        payment.p_category = category
214        payment.p_item = p_item
215        payment.p_session = p_session
216        payment.p_level = p_level
217        payment.p_current = p_current
218        payment.amount_auth = amount
219        return None, payment
220
221    # prefix
222    STUDENT_ID_PREFIX = u'R'
223
224    PORTRAIT_CHANGE_STATES = ()
Note: See TracBrowser for help on using the repository browser.