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

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

Use degree instead of certcode.

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