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

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

Acceptance Fee is ONLY FOR NEWLY ADMITTED STUDENTS.

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