source: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/utils.py @ 16125

Last change on this file since 16125 was 16091, checked in by Henrik Bettermann, 5 years ago

Add further states for fresh student tuition fee payments.

  • Property svn:keywords set to Id
File size: 9.4 KB
Line 
1## $Id: utils.py 16091 2020-05-18 11:56:47Z 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
19from time import time
20from zope.component import createObject, getUtility
21from waeup.kofa.interfaces import (IKofaUtils,
22    ADMITTED, CLEARANCE, REQUESTED, CLEARED, RETURNING, PAID,
23    REGISTERED, VALIDATED)
24from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
25from kofacustom.iuokada.interfaces import MessageFactory as _
26
27class CustomStudentsUtils(NigeriaStudentsUtils):
28    """A collection of customized methods.
29
30    """
31
32    # refix
33    STUDENT_ID_PREFIX = u'I'
34
35    SKIP_UPLOAD_VIEWLETS = (
36        'acceptanceletterupload', 'certificateupload'
37        )
38    # Maximum size of upload files in kB
39    MAX_KB = 500
40
41    #: A tuple containing the names of registration states in which changing of
42    #: passport pictures is allowed.
43    PORTRAIT_CHANGE_STATES = (ADMITTED, CLEARANCE,)
44
45    def warnCreditsOOR(self, studylevel, course=None):
46        """Return message if credits are out of range. In the base
47        package only maximum credits is set.
48        """
49        if course and studylevel.total_credits + course.credits > 60:
50            return _('Maximum credits exceeded.')
51        elif studylevel.total_credits > 60:
52            return _('Maximum credits exceeded.')
53        return
54
55    def setPaymentDetails(self, category, student,
56            previous_session, previous_level, combi=[]):
57        """Create a payment ticket and set the payment data of a
58        student for the payment category specified.
59        """
60        p_item = u''
61        amount = 0.0
62        if previous_session:
63            if previous_session < student['studycourse'].entry_session:
64                return _('The previous session must not fall below '
65                         'your entry session.'), None
66            if category == 'schoolfee':
67                # School fee is always paid for the following session
68                if previous_session > student['studycourse'].current_session:
69                    return _('This is not a previous session.'), None
70            else:
71                if previous_session > student['studycourse'].current_session - 1:
72                    return _('This is not a previous session.'), None
73            p_session = previous_session
74            p_level = previous_level
75            p_current = False
76        else:
77            p_session = student['studycourse'].current_session
78            p_level = student['studycourse'].current_level
79            p_current = True
80        academic_session = self._getSessionConfiguration(p_session)
81        if academic_session == None:
82            return _(u'Session configuration object is not available.'), None
83        # Determine fee.
84        if category in ('schoolfee', 'schoolfee40',
85                        'secondinstal'):
86            try:
87                certificate = student['studycourse'].certificate
88                p_item = certificate.code
89            except (AttributeError, TypeError):
90                return _('Study course data are incomplete.'), None
91            if previous_session:
92                # Students can pay for previous sessions in all
93                # workflow states.  Fresh students are excluded by the
94                # update method of the PreviousPaymentAddFormPage.
95                if previous_level == 100:
96                    amount = getattr(certificate, 'school_fee_1', 0.0)
97                else:
98                    amount = getattr(certificate, 'school_fee_2', 0.0)
99                if category == 'schoolfee40':
100                    amount = 0.4*amount
101                elif category == 'secondinstal':
102                    amount = 0.6*amount
103            else:
104                if category == 'secondinstal':
105                    if student.is_fresh:
106                        amount = 0.6 * getattr(certificate, 'school_fee_1', 0.0)
107                    else:
108                        amount = 0.6 * getattr(certificate, 'school_fee_2', 0.0)
109                else:
110                    if student.state in (CLEARANCE, REQUESTED, CLEARED):
111                        amount = getattr(certificate, 'school_fee_1', 0.0)
112                    elif student.state == RETURNING:
113                        # In case of returning school fee payment the
114                        # payment session and level contain the values of
115                        # the session the student has paid for. Payment
116                        # session is always next session.
117                        p_session, p_level = self.getReturningData(student)
118                        academic_session = self._getSessionConfiguration(p_session)
119                        if academic_session == None:
120                            return _(
121                                u'Session configuration object is not available.'
122                                ), None
123                        amount = getattr(certificate, 'school_fee_2', 0.0)
124                    elif student.is_postgrad and student.state == PAID:
125                        # Returning postgraduate students also pay for the
126                        # next session but their level always remains the
127                        # same.
128                        p_session += 1
129                        academic_session = self._getSessionConfiguration(p_session)
130                        if academic_session == None:
131                            return _(
132                                u'Session configuration object is not available.'
133                                ), None
134                        amount = getattr(certificate, 'school_fee_2', 0.0)
135                    if amount and category == 'schoolfee40':
136                        amount = 0.4*amount
137        elif category == 'clearance':
138            try:
139                p_item = student['studycourse'].certificate.code
140            except (AttributeError, TypeError):
141                return _('Study course data are incomplete.'), None
142            amount = academic_session.clearance_fee
143        elif category.startswith('resit'):
144            amount = academic_session.resit_fee
145            number = int(category.strip('resit'))
146            amount *= number
147        #elif category == 'bed_allocation':
148        #    p_item = self.getAccommodationDetails(student)['bt']
149        #    amount = academic_session.booking_fee
150        #elif category == 'hostel_maintenance':
151        #    amount = 0.0
152        #    bedticket = student['accommodation'].get(
153        #        str(student.current_session), None)
154        #    if bedticket is not None and bedticket.bed is not None:
155        #        p_item = bedticket.bed_coordinates
156        #        if bedticket.bed.__parent__.maint_fee > 0:
157        #            amount = bedticket.bed.__parent__.maint_fee
158        #        else:
159        #            # fallback
160        #            amount = academic_session.maint_fee
161        #    else:
162        #        return _(u'No bed allocated.'), None
163        elif category == 'combi' and combi:
164            categories = getUtility(IKofaUtils).COMBI_PAYMENT_CATEGORIES
165            for cat in combi:
166                fee_name = cat + '_fee'
167                cat_amount = getattr(academic_session, fee_name, 0.0)
168                if not cat_amount:
169                    return _('%s undefined.' % categories[cat]), None
170                amount += cat_amount
171                p_item += u'%s + ' % categories[cat]
172            p_item = p_item.strip(' + ')
173        else:
174            fee_name = category + '_fee'
175            amount = getattr(academic_session, fee_name, 0.0)
176        if amount in (0.0, None):
177            return _('Amount could not be determined.'), None
178        if self.samePaymentMade(student, category, p_item, p_session):
179            return _('This type of payment has already been made.'), None
180        if self._isPaymentDisabled(p_session, category, student):
181            return _('This category of payments has been disabled.'), None
182        payment = createObject(u'waeup.StudentOnlinePayment')
183        timestamp = ("%d" % int(time()*10000))[1:]
184        payment.p_id = "p%s" % timestamp
185        payment.p_category = category
186        payment.p_item = p_item
187        payment.p_session = p_session
188        payment.p_level = p_level
189        payment.p_current = p_current
190        payment.amount_auth = amount
191        payment.p_combi = combi
192        return None, payment
193
194    def constructMatricNumber(self, student):
195        """Fetch the matric number counter which fits the student and
196        construct the new matric number of the student.
197        """
198        next_integer = grok.getSite()['configuration'].next_matric_integer
199        if next_integer == 0:
200            return _('Matriculation number cannot be set.'), None
201        if not student.state in (
202            RETURNING, CLEARED, PAID, REGISTERED, VALIDATED):
203            return _('Matriculation number cannot be set.'), None
204        year = unicode(student.entry_session)[2:]
205        return None, "%s/%06d" % (year, next_integer)
Note: See TracBrowser for help on using the repository browser.