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
RevLine 
[7419]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##
[7151]18import grok
[9190]19import random
[8599]20from time import time
[9737]21from zope.component import createObject, getUtility
[8475]22from waeup.kofa.interfaces import CLEARED, RETURNING, PAID
[8834]23from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
[8247]24from waeup.kofa.accesscodes import create_accesscode
[9737]25from waeup.kofa.interfaces import CLEARED, RETURNING, IKofaUtils
[9393]26from waeup.kofa.fees import FeeTable
[9347]27from waeup.kwarapoly.interfaces import MessageFactory as _
[6902]28
[9393]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          (
[9528]41            (34400.0, 36600.0, 29500.0, 28800.0, 0.0, 38700.0, 30700.0, 29900.0, 0.0, 47250.0), # science
[9568]42            (34400.0, 35100.0, 28000.0, 27300.0, 0.0, 37200.0, 29200.0, 28400.0, 0.0, 47250.0)  # arts
[9393]43          ), # local
44          (
[9568]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
[9393]47          ), # non-local
48        ), # ft
49        (
50          (
[9568]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
[9393]53          ), # local
54          (
[9528]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
[9393]57          ), # non-local
58        ), # pt
59    )
60
61SCHOOL_FEES = FeeTable(FEES_PARAMS, FEES_VALUES)
62
63def local_nonlocal(student):
64    lga = getattr(student, 'lga')
[9568]65    if lga and lga.startswith('kwara'):
[9393]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
[8834]82class CustomStudentsUtils(NigeriaStudentsUtils):
[7151]83    """A collection of customized methods.
84
85    """
86
[9393]87
[9190]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
[8270]94    def getReturningData(self, student):
95        """ This method defines what happens after school fee payment
[8319]96        of returning students depending on the student's senate verdict.
[8270]97        """
[8319]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
[8270]110        new_session = student['studycourse'].current_session + 1
111        return new_session, new_level
112
[9153]113    def setPaymentDetails(self, category, student,
114            previous_session=None, previous_level=None):
[8599]115        """Create Payment object and set the payment data of a student for
116        the payment category specified.
117
118        """
[8306]119        details = {}
[8599]120        p_item = u''
121        amount = 0.0
122        error = u''
[9153]123        if previous_session:
124            return _('Previous session payment not yet implemented.'), None
[8599]125        p_session = student['studycourse'].current_session
126        p_level = student['studycourse'].current_level
[9153]127        p_current = True
[9526]128        academic_session = self._getSessionConfiguration(p_session)
129        if academic_session == None:
[8599]130            return _(u'Session configuration object is not available.'), None
[9526]131        # Determine fee.
[7151]132        if category == 'transfer':
[8599]133            amount = academic_session.transfer_fee
[7151]134        elif category == 'gown':
[8599]135            amount = academic_session.gown_fee
[7151]136        elif category == 'bed_allocation':
[8599]137            amount = academic_session.booking_fee
[7151]138        elif category == 'hostel_maintenance':
[8599]139            amount = academic_session.maint_fee
[7151]140        elif category == 'clearance':
[9143]141            amount = academic_session.clearance_fee
[8599]142            try:
143                p_item = student['studycourse'].certificate.code
144            except (AttributeError, TypeError):
145                return _('Study course data are incomplete.'), None
[7151]146        elif category == 'schoolfee':
[8599]147            try:
148                certificate = student['studycourse'].certificate
149                p_item = certificate.code
150            except (AttributeError, TypeError):
151                return _('Study course data are incomplete.'), None
[9297]152            if student.state == RETURNING:
[9526]153                # Override p_session and p_level
[9297]154                p_session, p_level = self.getReturningData(student)
[9526]155                academic_session = self._getSessionConfiguration(p_session)
156                if academic_session == None:
157                    return _(u'Session configuration object is not available.'), None
[9388]158            if student.state in (RETURNING, CLEARED):
[9393]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                        )
[9737]166        elif category == 'carryover1':
[9724]167            amount = 6000.0
[9737]168        elif category == 'carryover2':
[9724]169            amount = 7000.0
[9737]170        elif category == 'carryover3':
[9724]171            amount = 8000.0
[8599]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
[9737]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'
[8713]186        payment = createObject(u'waeup.StudentOnlinePayment')
[8953]187        timestamp = ("%d" % int(time()*10000))[1:]
[8599]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
[9153]193        payment.p_current = p_current
[9143]194        payment.amount_auth = float(amount)
[8599]195        return None, payment
[7621]196
[9207]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'
[9614]217        elif current_level in (100, 400):
[9207]218            bt = 'fr'
[9614]219        elif current_level in (300, 600):
[9207]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
[9347]231    # KwaraPoly prefix
[9366]232    STUDENT_ID_PREFIX = u'W'
Note: See TracBrowser for help on using the repository browser.