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

Last change on this file since 14195 was 14160, checked in by Henrik Bettermann, 8 years ago

Customize getDegreeClassNumbe.

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