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

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

Disable returning students from being able to "delete" or change passport.

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