source: main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/students/utils.py @ 9769

Last change on this file since 9769 was 9737, checked in by Henrik Bettermann, 12 years ago

Use carryover categories only for calculation of fee, then change to schoolfee.

Configure SELECTABLE_PAYMENT_CATEGORIES.

Add and adjust tests.

  • Property svn:keywords set to Id
File size: 8.7 KB
Line 
1## $Id: utils.py 9737 2012-11-28 17:00:43Z 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
19import random
20from time import time
21from zope.component import createObject, getUtility
22from waeup.kofa.interfaces import CLEARED, RETURNING, PAID
23from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
24from waeup.kofa.accesscodes import create_accesscode
25from waeup.kofa.interfaces import CLEARED, RETURNING, IKofaUtils
26from waeup.kofa.fees import FeeTable
27from waeup.kwarapoly.interfaces import MessageFactory as _
28
29PAYMENT_LEVELS = (10, 100, 200, 210, 300, 400, 500, 510, 600, 999)
30
31FEES_PARAMS = (
32        ('ft', 'pt'),
33        ('local', 'non-local'),
34        ('science','arts'),
35        PAYMENT_LEVELS
36    )
37
38FEES_VALUES = (
39        (
40          (
41            (34400.0, 36600.0, 29500.0, 28800.0, 0.0, 38700.0, 30700.0, 29900.0, 0.0, 47250.0), # science
42            (34400.0, 35100.0, 28000.0, 27300.0, 0.0, 37200.0, 29200.0, 28400.0, 0.0, 47250.0)  # arts
43          ), # local
44          (
45            (49500.0, 52100.0, 38850.0, 35900.0, 0.0, 55600.0, 40850.0, 38600.0, 0.0, 71880.0), # science
46            (49500.0, 50600.0, 37350.0, 34400.0, 0.0, 54100.0, 39350.0, 37100.0, 0.0, 71880.0)  # arts
47          ), # non-local
48        ), # ft
49        (
50          (
51            (0.0, 39400.0, 30900.0, 0.0, 30900.0, 39900.0, 31050.0, 0.0, 31050.0, 0.0), # science
52            (0.0, 37900.0, 29400.0, 0.0, 29400.0, 38400.0, 29550.0, 0.0, 29550.0, 0.0)  # arts
53          ), # local
54          (
55            (0.0, 54600.0, 32350.0, 0.0, 32350.0, 57100.0, 42350.0, 0.0, 42350.0, 0.0), # science
56            (0.0, 53100.0, 30850.0, 0.0, 30850.0, 55600.0, 40850.0, 0.0, 40850.0, 0.0)  # arts
57          ), # non-local
58        ), # pt
59    )
60
61SCHOOL_FEES = FeeTable(FEES_PARAMS, FEES_VALUES)
62
63def local_nonlocal(student):
64    lga = getattr(student, 'lga')
65    if lga and lga.startswith('kwara'):
66        return 'local'
67    else:
68        return 'non-local'
69
70def arts_science(student):
71    if student.faccode == 'IFMS':
72        return 'arts'
73    else:
74        return 'science'
75
76def pt_ft(student):
77    if student.current_mode.endswith('pt'):
78        return 'pt'
79    else:
80        return 'ft'
81
82class CustomStudentsUtils(NigeriaStudentsUtils):
83    """A collection of customized methods.
84
85    """
86
87
88    def selectBed(self, available_beds):
89        """Randomly select a bed from a list of available beds.
90
91        """
92        return random.choice(available_beds)
93
94    def getReturningData(self, student):
95        """ This method defines what happens after school fee payment
96        of returning students depending on the student's senate verdict.
97        """
98        prev_level = student['studycourse'].current_level
99        cur_verdict = student['studycourse'].current_verdict
100        if cur_verdict in ('A','B','L','M','N','Z',):
101            # Successful student
102            new_level = divmod(int(prev_level),100)[0]*100 + 100
103        elif cur_verdict == 'C':
104            # Student on probation
105            new_level = int(prev_level) + 10
106        else:
107            # Student is somehow in an undefined state.
108            # Level has to be set manually.
109            new_level = prev_level
110        new_session = student['studycourse'].current_session + 1
111        return new_session, new_level
112
113    def setPaymentDetails(self, category, student,
114            previous_session=None, previous_level=None):
115        """Create Payment object and set the payment data of a student for
116        the payment category specified.
117
118        """
119        details = {}
120        p_item = u''
121        amount = 0.0
122        error = u''
123        if previous_session:
124            return _('Previous session payment not yet implemented.'), None
125        p_session = student['studycourse'].current_session
126        p_level = student['studycourse'].current_level
127        p_current = True
128        academic_session = self._getSessionConfiguration(p_session)
129        if academic_session == None:
130            return _(u'Session configuration object is not available.'), None
131        # Determine fee.
132        if category == 'transfer':
133            amount = academic_session.transfer_fee
134        elif category == 'gown':
135            amount = academic_session.gown_fee
136        elif category == 'bed_allocation':
137            amount = academic_session.booking_fee
138        elif category == 'hostel_maintenance':
139            amount = academic_session.maint_fee
140        elif category == 'clearance':
141            amount = academic_session.clearance_fee
142            try:
143                p_item = student['studycourse'].certificate.code
144            except (AttributeError, TypeError):
145                return _('Study course data are incomplete.'), None
146        elif category == 'schoolfee':
147            try:
148                certificate = student['studycourse'].certificate
149                p_item = certificate.code
150            except (AttributeError, TypeError):
151                return _('Study course data are incomplete.'), None
152            if student.state == RETURNING:
153                # Override p_session and p_level
154                p_session, p_level = self.getReturningData(student)
155                academic_session = self._getSessionConfiguration(p_session)
156                if academic_session == None:
157                    return _(u'Session configuration object is not available.'), None
158            if student.state in (RETURNING, CLEARED):
159                if p_level in PAYMENT_LEVELS:
160                    amount = SCHOOL_FEES.get_fee(
161                        (pt_ft(student),
162                         local_nonlocal(student),
163                         arts_science(student),
164                         p_level)
165                        )
166        elif category == 'carryover1':
167            amount = 6000.0
168        elif category == 'carryover2':
169            amount = 7000.0
170        elif category == 'carryover3':
171            amount = 8000.0
172        if amount in (0.0, None):
173            return _(u'Amount could not be determined.'), None
174        for key in student['payments'].keys():
175            ticket = student['payments'][key]
176            if ticket.p_state == 'paid' and\
177               ticket.p_category == category and \
178               ticket.p_item == p_item and \
179               ticket.p_session == p_session:
180                  return _('This type of payment has already been made.'), None
181        if category.startswith('carryover'):
182            p_item = getUtility(IKofaUtils).PAYMENT_CATEGORIES[category]
183            p_item = unicode(p_item)
184            # Now we change the category to reduce the number of categories.
185            category = 'schoolfee'
186        payment = createObject(u'waeup.StudentOnlinePayment')
187        timestamp = ("%d" % int(time()*10000))[1:]
188        payment.p_id = "p%s" % timestamp
189        payment.p_category = category
190        payment.p_item = p_item
191        payment.p_session = p_session
192        payment.p_level = p_level
193        payment.p_current = p_current
194        payment.amount_auth = float(amount)
195        return None, payment
196
197    def getAccommodationDetails(self, student):
198        """Determine the accommodation data of a student.
199        """
200        d = {}
201        d['error'] = u''
202        hostels = grok.getSite()['hostels']
203        d['booking_session'] = hostels.accommodation_session
204        d['allowed_states'] = hostels.accommodation_states
205        d['startdate'] = hostels.startdate
206        d['enddate'] = hostels.enddate
207        d['expired'] = hostels.expired
208        # Determine bed type
209        studycourse = student['studycourse']
210        certificate = getattr(studycourse,'certificate',None)
211        current_level = studycourse.current_level
212        if None in (current_level, certificate):
213            return d
214        end_level = certificate.end_level
215        if current_level == 10:
216            bt = 'pr'
217        elif current_level in (100, 400):
218            bt = 'fr'
219        elif current_level in (300, 600):
220            bt = 'fi'
221        else:
222            bt = 're'
223        if student.sex == 'f':
224            sex = 'female'
225        else:
226            sex = 'male'
227        special_handling = 'regular'
228        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
229        return d
230
231    # KwaraPoly prefix
232    STUDENT_ID_PREFIX = u'W'
Note: See TracBrowser for help on using the repository browser.