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

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

Configure repeater fees.

Fix test. assertMatches is not suitable for testing exact values.

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