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

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

Change flash message.

  • Property svn:keywords set to Id
File size: 16.5 KB
Line 
1## $Id: utils.py 13798 2016-04-04 09:05:53Z 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, GATEWAY_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        elif student.current_mode in ('dp_ft',):
57            grok.getSite()['configuration'].next_matric_integer_4 += 1
58            return
59        grok.getSite()['configuration'].next_matric_integer_2 += 1
60        return
61
62    def _concessionalPaymentMade(self, student):
63        if len(student['payments']):
64            for ticket in student['payments'].values():
65                if ticket.p_state == 'paid' and \
66                    ticket.p_category == 'concessional':
67                    return True
68        return False
69
70    def constructMatricNumber(self, student):
71        faccode = student.faccode
72        depcode = student.depcode
73        certcode = student.certcode
74        degree = getattr(
75            getattr(student.get('studycourse', None), 'certificate', None),
76                'degree', None)
77        year = unicode(student.entry_session)[2:]
78        if not student.state in (PAID, ) or not student.is_fresh or \
79            student.current_mode == 'found':
80            return _('Matriculation number cannot be set.'), None
81        #if student.current_mode not in ('mug_ft', 'mde_ft') and \
82        #    not self._concessionalPaymentMade(student):
83        #    return _('Matriculation number cannot be set.'), None
84        if student.is_postgrad:
85            next_integer = grok.getSite()['configuration'].next_matric_integer_3
86            if not degree or next_integer == 0:
87                return _('Matriculation number cannot be set.'), None
88            return None, "AAU/SPS/%s/%s/%s/%s/%05d" % (
89                faccode, depcode, year, degree, next_integer)
90        if student.current_mode in ('ug_pt', 'de_pt'):
91            next_integer = grok.getSite()['configuration'].next_matric_integer
92            if next_integer == 0:
93                return _('Matriculation number cannot be set.'), None
94            return None, "PTP/%s/%s/%s/%05d" % (
95                faccode, depcode, year, next_integer)
96        if student.current_mode in ('dp_ft',):
97            next_integer = grok.getSite()['configuration'].next_matric_integer_4
98            if next_integer == 0:
99                return _('Matriculation number cannot be set.'), None
100            return None, "IOE/DIP/%s/%05d" % (year, next_integer)
101        next_integer = grok.getSite()['configuration'].next_matric_integer_2
102        if next_integer == 0:
103            return _('Matriculation number cannot be set.'), None
104        if student.faccode in ('FBM', 'FCS'):
105            return None, "CMS/%s/%s/%s/%05d" % (
106                faccode, depcode, year, next_integer)
107        return None, "%s/%s/%s/%05d" % (faccode, depcode, year, next_integer)
108
109    def getReturningData(self, student):
110        """ This method defines what happens after school fee payment
111        of returning students depending on the student's senate verdict.
112        """
113        prev_level = student['studycourse'].current_level
114        cur_verdict = student['studycourse'].current_verdict
115        if cur_verdict in ('A','B','L','M','N','Z',):
116            # Successful student
117            new_level = divmod(int(prev_level),100)[0]*100 + 100
118        elif cur_verdict == 'C':
119            # Student on probation
120            new_level = int(prev_level) + 10
121        else:
122            # Student is somehow in an undefined state.
123            # Level has to be set manually.
124            new_level = prev_level
125        new_session = student['studycourse'].current_session + 1
126        return new_session, new_level
127
128    def _isPaymentDisabled(self, p_session, category, student):
129        academic_session = self._getSessionConfiguration(p_session)
130        if category.startswith('schoolfee') and \
131            'sf_all' in academic_session.payment_disabled:
132            return True
133        if category.startswith('clearance') and \
134            'cl_regular' in academic_session.payment_disabled and \
135            student.current_mode in ('ug_ft', 'de_ft', 'mug_ft', 'mde_ft'):
136            return True
137        if category == 'hostel_maintenance' and \
138            'maint_all' in academic_session.payment_disabled:
139            return True
140        return False
141
142    def setPaymentDetails(self, category, student,
143            previous_session=None, previous_level=None):
144        """Create Payment object and set the payment data of a student for
145        the payment category specified.
146
147        """
148        details = {}
149        p_item = u''
150        amount = 0.0
151        error = u''
152        if previous_session:
153            return _('Previous session payment not yet implemented.'), None
154        p_session = student['studycourse'].current_session
155        p_level = student['studycourse'].current_level
156        p_current = True
157        academic_session = self._getSessionConfiguration(p_session)
158        if academic_session == None:
159            return _(u'Session configuration object is not available.'), None
160        # Determine fee.
161        if category == 'transfer':
162            amount = academic_session.transfer_fee
163        elif category == 'transcript':
164            amount = academic_session.transcript_fee
165        elif category == 'bed_allocation':
166            amount = academic_session.booking_fee
167        elif category == 'hostel_maintenance':
168            amount = 0.0
169            bedticket = student['accommodation'].get(
170                str(student.current_session), None)
171            if bedticket is not None and bedticket.bed is not None:
172                p_item = bedticket.display_coordinates
173                if bedticket.bed.__parent__.maint_fee > 0:
174                    amount = bedticket.bed.__parent__.maint_fee
175                else:
176                    # fallback
177                    amount = academic_session.maint_fee
178            else:
179                return _(u'No bed allocated.'), None
180        elif category == 'welfare':
181            amount = academic_session.welfare_fee
182        elif category == 'union':
183            amount = academic_session.union_fee
184        elif category == 'lapel':
185            amount = academic_session.lapel_fee
186        elif category == 'matric_gown':
187            amount = academic_session.matric_gown_fee
188        elif category == 'concessional':
189            amount = academic_session.concessional_fee
190        elif student.current_mode == 'found' and category not in (
191            'schoolfee', 'clearance', 'late_registration'):
192            return _('Not allowed.'), None
193        elif category.startswith('clearance'):
194            if student.state not in (ADMITTED, CLEARANCE, REQUESTED, CLEARED):
195                return _(u'Acceptance Fee payments not allowed.'), None
196            if student.faccode == 'FP':
197                amount = academic_session.clearance_fee_fp
198            elif student.current_mode.endswith('_pt'):
199                if student.is_postgrad:
200                    amount = academic_session.clearance_fee_pg_pt
201                else:
202                    amount = academic_session.clearance_fee_ug_pt
203            elif student.faccode == 'FCS':
204                # Students in clinical medical sciences pay the medical
205                # acceptance fee
206                amount = academic_session.clearance_fee_med
207            elif student.is_postgrad:  # and not part-time
208                amount = academic_session.clearance_fee_pg
209            else:
210                amount = academic_session.clearance_fee
211            p_item = student['studycourse'].certificate.code
212            if amount in (0.0, None):
213                return _(u'Amount could not be determined.'), None
214            # Add Matric Gown Fee and Lapel Fee
215            if category == 'clearance_incl':
216                amount += gateway_net_amt(academic_session.matric_gown_fee) + \
217                    gateway_net_amt(academic_session.lapel_fee)
218        elif category == 'late_registration':
219            amount = academic_session.late_registration_fee
220        elif category.startswith('schoolfee'):
221            try:
222                certificate = student['studycourse'].certificate
223                p_item = certificate.code
224            except (AttributeError, TypeError):
225                return _('Study course data are incomplete.'), None
226            if category in ('schoolfee_1', 'schoolfee_2'):
227                if student.current_mode == 'ug_pt':
228                    return _("Part-time students are not allowed "
229                             "to pay by instalments."), None
230                if category == 'schoolfee_1' and student.state != CLEARED:
231                    return _("Wrong state. Only students in state 'cleared' "
232                             "are allowed to pay by instalments."), None
233            if student.state == CLEARED or category == 'schoolfee_2':
234                if student.is_foreigner:
235                    amount = getattr(certificate, 'school_fee_3', 0.0)
236                else:
237                    amount = getattr(certificate, 'school_fee_1', 0.0)
238                # Cut school fee by 50%
239                if category in ('schoolfee_1', 'schoolfee_2'):
240                    if amount:
241                        amount = gateway_net_amt(amount) / 2 + GATEWAY_AMT
242            elif student.state == RETURNING:
243                if student.is_postgrad and category == 'schoolfee_incl':
244                    return _("No additional fees required."), None
245                if not student.father_name:
246                    return _("Personal data form is not properly filled."), None
247                # In case of returning school fee payment the payment session
248                # and level contain the values of the session the student
249                # has paid for.
250                p_session, p_level = self.getReturningData(student)
251                try:
252                    academic_session = grok.getSite()[
253                        'configuration'][str(p_session)]
254                except KeyError:
255                    return _(u'Session configuration object is not available.'), None
256                if student.is_foreigner:
257                    amount = getattr(certificate, 'school_fee_4', 0.0)
258                else:
259                    amount = getattr(certificate, 'school_fee_2', 0.0)
260            else:
261                return _('Wrong state.'), None
262            if amount in (0.0, None):
263                return _(u'Amount could not be determined.'), None
264            # Add Student Union Fee and Welfare Assurance
265            if category in ('schoolfee_incl', 'schoolfee_1'):
266                amount += gateway_net_amt(academic_session.welfare_fee) + \
267                    gateway_net_amt(academic_session.union_fee)
268            # Add non-indigenous fee and session specific penalty fees
269            if student.is_postgrad:
270                amount += academic_session.penalty_pg
271                if not student.lga.startswith('edo'):
272                    amount += 20000.0
273            else:
274                amount += academic_session.penalty_ug
275        if amount in (0.0, None):
276            return _(u'Amount could not be determined.'), None
277        # Create ticket.
278        for key in student['payments'].keys():
279            ticket = student['payments'][key]
280            if ticket.p_state == 'paid' and\
281               ticket.p_category == category and \
282               ticket.p_item == p_item and \
283               ticket.p_session == p_session:
284                  return _('This type of payment has already been made.'), None
285            # Additional condition in AAUE
286            if category in ('schoolfee', 'schoolfee_incl', 'schoolfee_1'):
287                if ticket.p_state == 'paid' and \
288                   ticket.p_category in ('schoolfee',
289                                         'schoolfee_incl',
290                                         'schoolfee_1') and \
291                   ticket.p_item == p_item and \
292                   ticket.p_session == p_session:
293                      return _(
294                          'Another school fee payment for this '
295                          'session has already been made.'), None
296
297        if self._isPaymentDisabled(p_session, category, student):
298            return _('This category of payments has been disabled.'), None
299        payment = createObject(u'waeup.StudentOnlinePayment')
300        timestamp = ("%d" % int(time()*10000))[1:]
301        payment.p_id = "p%s" % timestamp
302        payment.p_category = category
303        payment.p_item = p_item
304        payment.p_session = p_session
305        payment.p_level = p_level
306        payment.p_current = p_current
307        payment.amount_auth = amount
308        return None, payment
309
310    def _admissionText(self, student, portal_language):
311        inst_name = grok.getSite()['configuration'].name
312        entry_session = student['studycourse'].entry_session
313        entry_session = academic_sessions_vocab.getTerm(entry_session).title
314        text = trans(_(
315            'This is to inform you that you have been offered provisional'
316            ' admission into ${a} for the ${b} academic session as follows:',
317            mapping = {'a': inst_name, 'b': entry_session}),
318            portal_language)
319        return text
320
321    def maxCredits(self, studylevel):
322        """Return maximum credits.
323
324        """
325        return 48
326
327    def getBedCoordinates(self, bedticket):
328        """Return descriptive bed coordinates.
329        This method can be used to customize the `display_coordinates`
330        property method in order to  display a
331        customary description of the bed space.
332        """
333        bc = bedticket.bed_coordinates.split(',')
334        if len(bc) == 4:
335            return bc[0]
336        return bedticket.bed_coordinates
337
338    def getAccommodationDetails(self, student):
339        """Determine the accommodation data of a student.
340        """
341        d = {}
342        d['error'] = u''
343        hostels = grok.getSite()['hostels']
344        d['booking_session'] = hostels.accommodation_session
345        d['allowed_states'] = hostels.accommodation_states
346        d['startdate'] = hostels.startdate
347        d['enddate'] = hostels.enddate
348        d['expired'] = hostels.expired
349        # Determine bed type
350        bt = 'all'
351        if student.sex == 'f':
352            sex = 'female'
353        else:
354            sex = 'male'
355        special_handling = 'regular'
356        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
357        return d
358
359    def checkAccommodationRequirements(self, student, acc_details):
360        super(CustomStudentsUtils, self).checkAccommodationRequirements(
361            student, acc_details)
362        if student.current_mode not in ('ug_ft', 'de_ft', 'mug_ft', 'mde_ft'):
363            return _('You are not eligible to book accommodation.')
364        return
365
366    # AAUE prefix
367    STUDENT_ID_PREFIX = u'E'
Note: See TracBrowser for help on using the repository browser.