source: main/waeup.aaue/trunk/src/waeup/aaue/students/utils.py @ 13490

Last change on this file since 13490 was 13482, checked in by Henrik Bettermann, 9 years ago

Personal data form must be filled before paying school fees.

  • Property svn:keywords set to Id
File size: 12.5 KB
Line 
1## $Id: utils.py 13482 2015-11-19 05:26:44Z 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
21from waeup.kofa.interfaces import (
22    ADMITTED, CLEARED, RETURNING, PAID, academic_sessions_vocab)
23from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
24from waeup.kofa.accesscodes import create_accesscode
25from waeup.kofa.students.utils import trans
26from waeup.aaue.interswitch.browser import gateway_net_amt
27from waeup.aaue.interfaces import MessageFactory as _
28
29class CustomStudentsUtils(NigeriaStudentsUtils):
30    """A collection of customized methods.
31
32    """
33
34    PORTRAIT_CHANGE_STATES = (ADMITTED, RETURNING)
35
36    gpa_boundaries = ((1, 'FRNS'),
37                      (1.5, 'Pass'),
38                      (2.4, '3rd Class Honours'),
39                      (3.5, '2nd Class Honours Lower Division'),
40                      (4.5, '2nd Class Honours Upper Division'),
41                      (5, '1st Class Honours'))
42
43    def increaseMatricInteger(self, student):
44        """Increase counter for matric numbers.
45        This counter can be a centrally stored attribute or an attribute of
46        faculties, departments or certificates. In the base package the counter
47        is as an attribute of the site configuration container.
48        """
49        if student.current_mode in ('ug_pt', 'de_pt'):
50            grok.getSite()['configuration'].next_matric_integer += 1
51            return
52        grok.getSite()['configuration'].next_matric_integer_2 += 1
53        return
54
55    def constructMatricNumber(self, student):
56        faccode = student.faccode
57        depcode = student.depcode
58        year = unicode(student.entry_session)[2:]
59        if not student.state in (PAID, ) or not student.is_fresh or \
60            student.current_mode == 'found':
61            return _('Matriculation number cannot be set.'), None
62        if student.current_mode in ('ug_pt', 'de_pt'):
63            next_integer = grok.getSite()['configuration'].next_matric_integer
64            if next_integer == 0:
65                return _('Matriculation number cannot be set.'), None
66            return None, "PTP/%s/%s/%s/%05d" % (
67                faccode, depcode, year, next_integer)
68        next_integer = grok.getSite()['configuration'].next_matric_integer_2
69        if next_integer == 0:
70            return _('Matriculation number cannot be set.'), None
71        if student.faccode in ('FBM', 'FCS'):
72            return None, "CMS/%s/%s/%s/%05d" % (
73                faccode, depcode, year, next_integer)
74        return None, "%s/%s/%s/%05d" % (faccode, depcode, year, next_integer)
75
76    def getReturningData(self, student):
77        """ This method defines what happens after school fee payment
78        of returning students depending on the student's senate verdict.
79        """
80        prev_level = student['studycourse'].current_level
81        cur_verdict = student['studycourse'].current_verdict
82        if cur_verdict in ('A','B','L','M','N','Z',):
83            # Successful student
84            new_level = divmod(int(prev_level),100)[0]*100 + 100
85        elif cur_verdict == 'C':
86            # Student on probation
87            new_level = int(prev_level) + 10
88        else:
89            # Student is somehow in an undefined state.
90            # Level has to be set manually.
91            new_level = prev_level
92        new_session = student['studycourse'].current_session + 1
93        return new_session, new_level
94
95    def _isPaymentDisabled(self, p_session, category, student):
96        academic_session = self._getSessionConfiguration(p_session)
97        if category == 'schoolfee' and \
98            'sf_all' in academic_session.payment_disabled:
99            return True
100        if category == 'hostel_maintenance' and \
101            'maint_all' in academic_session.payment_disabled:
102            return True
103        return False
104
105    def setPaymentDetails(self, category, student,
106            previous_session=None, previous_level=None):
107        """Create Payment object and set the payment data of a student for
108        the payment category specified.
109
110        """
111        details = {}
112        p_item = u''
113        amount = 0.0
114        error = u''
115        if previous_session:
116            return _('Previous session payment not yet implemented.'), None
117        p_session = student['studycourse'].current_session
118        p_level = student['studycourse'].current_level
119        p_current = True
120        academic_session = self._getSessionConfiguration(p_session)
121        if academic_session == None:
122            return _(u'Session configuration object is not available.'), None
123        # Determine fee.
124        if category == 'transfer':
125            amount = academic_session.transfer_fee
126        elif category == 'transcript':
127            amount = academic_session.transcript_fee
128        elif category == 'bed_allocation':
129            amount = academic_session.booking_fee
130        elif category == 'hostel_maintenance':
131            amount = 0.0
132            bedticket = student['accommodation'].get(
133                str(student.current_session), None)
134            if bedticket:
135                p_item = bedticket.display_coordinates
136                if bedticket.bed.__parent__.maint_fee > 0:
137                    amount = bedticket.bed.__parent__.maint_fee
138                else:
139                    # fallback
140                    amount = academic_session.maint_fee
141            else:
142                # Should not happen because this is already checked
143                # in the browser module, but anyway ...
144                portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
145                p_item = trans(_('no bed allocated'), portal_language)
146        elif category == 'welfare':
147            amount = academic_session.welfare_fee
148        elif category == 'union':
149            amount = academic_session.union_fee
150        elif category == 'lapel':
151            amount = academic_session.lapel_fee
152        elif category == 'matric_gown':
153            amount = academic_session.matric_gown_fee
154        elif category == 'concessional':
155            amount = academic_session.concessional_fee
156        elif category.startswith('clearance'):
157            if student.faccode == 'FP':
158                amount = academic_session.clearance_fee_fp
159            elif student.current_mode.endswith('_pt'):
160                amount = academic_session.clearance_fee_pt
161            elif student.faccode == 'FCS':
162                # Students in clinical medical sciences pay the medical
163                # acceptance fee
164                amount = academic_session.clearance_fee_med
165            else:
166                amount = academic_session.clearance_fee
167            p_item = student['studycourse'].certificate.code
168            # Add Matric Gown Fee and Lapel Fee
169            if category.endswith('_incl'):
170                if amount is None:
171                    # Otherwise we can't add somtehing
172                    amount = 0.0
173                amount += gateway_net_amt(academic_session.matric_gown_fee) + \
174                    gateway_net_amt(academic_session.lapel_fee)
175        elif category == 'late_registration':
176            amount = academic_session.late_registration_fee
177        elif category.startswith('schoolfee'):
178            try:
179                certificate = student['studycourse'].certificate
180                p_item = certificate.code
181            except (AttributeError, TypeError):
182                return _('Study course data are incomplete.'), None
183            if student.state == CLEARED:
184                if student.is_foreigner:
185                    amount = getattr(certificate, 'school_fee_3', 0.0)
186                else:
187                    amount = getattr(certificate, 'school_fee_1', 0.0)
188            elif student.state == RETURNING:
189                if not student.father_name:
190                    return _("Personal data form is not properly filled."), None
191                # In case of returning school fee payment the payment session
192                # and level contain the values of the session the student
193                # has paid for.
194                p_session, p_level = self.getReturningData(student)
195                try:
196                    academic_session = grok.getSite()[
197                        'configuration'][str(p_session)]
198                except KeyError:
199                    return _(u'Session configuration object is not available.'), None
200                if student.is_foreigner:
201                    amount = getattr(certificate, 'school_fee_4', 0.0)
202                else:
203                    amount = getattr(certificate, 'school_fee_2', 0.0)
204            else:
205                return _('Wrong state.'), None
206            if amount in (0.0, None):
207                return _(u'Amount could not be determined.'), None
208            # Add Student Union Fee and Welfare Assurance
209            if category == 'schoolfee_incl':
210                amount += gateway_net_amt(academic_session.welfare_fee) + \
211                    gateway_net_amt(academic_session.union_fee)
212        if amount in (0.0, None):
213            return _(u'Amount could not be determined.'), None
214        # Add session specific penalty fee.
215        if category.startswith('schoolfee') and student.is_postgrad:
216            amount += academic_session.penalty_pg
217        elif category.startswith('schoolfee'):
218            amount += academic_session.penalty_ug
219        # Create ticket.
220        for key in student['payments'].keys():
221            ticket = student['payments'][key]
222            if ticket.p_state == 'paid' and\
223               ticket.p_category == category and \
224               ticket.p_item == p_item and \
225               ticket.p_session == p_session:
226                  return _('This type of payment has already been made.'), None
227        if self._isPaymentDisabled(p_session, category, student):
228            return _('Payment temporarily disabled.'), None
229        payment = createObject(u'waeup.StudentOnlinePayment')
230        timestamp = ("%d" % int(time()*10000))[1:]
231        payment.p_id = "p%s" % timestamp
232        payment.p_category = category
233        payment.p_item = p_item
234        payment.p_session = p_session
235        payment.p_level = p_level
236        payment.p_current = p_current
237        payment.amount_auth = amount
238        return None, payment
239
240    def _admissionText(self, student, portal_language):
241        inst_name = grok.getSite()['configuration'].name
242        entry_session = student['studycourse'].entry_session
243        entry_session = academic_sessions_vocab.getTerm(entry_session).title
244        text = trans(_(
245            'This is to inform you that you have been offered provisional'
246            ' admission into ${a} for the ${b} academic session as follows:',
247            mapping = {'a': inst_name, 'b': entry_session}),
248            portal_language)
249        return text
250
251    def maxCredits(self, studylevel):
252        """Return maximum credits.
253
254        """
255        return 48
256
257    def getBedCoordinates(self, bedticket):
258        """Return descriptive bed coordinates.
259        This method can be used to customize the `display_coordinates`
260        property method in order to  display a
261        customary description of the bed space.
262        """
263        bc = bedticket.bed_coordinates.split(',')
264        if len(bc) == 4:
265            return bc[0]
266        return bedticket.bed_coordinates
267
268    def getAccommodationDetails(self, student):
269        """Determine the accommodation data of a student.
270        """
271        d = {}
272        d['error'] = u''
273        hostels = grok.getSite()['hostels']
274        d['booking_session'] = hostels.accommodation_session
275        d['allowed_states'] = hostels.accommodation_states
276        d['startdate'] = hostels.startdate
277        d['enddate'] = hostels.enddate
278        d['expired'] = hostels.expired
279        # Determine bed type
280        bt = 'all'
281        if student.sex == 'f':
282            sex = 'female'
283        else:
284            sex = 'male'
285        special_handling = 'regular'
286        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
287        return d
288
289    # AAUE prefix
290    STUDENT_ID_PREFIX = u'E'
Note: See TracBrowser for help on using the repository browser.