source: main/waeup.uniben/trunk/src/waeup/uniben/students/utils.py @ 13448

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

Add more certificates to special_handling category.

  • Property svn:keywords set to Id
File size: 17.7 KB
Line 
1## $Id: utils.py 13448 2015-11-12 16:56:18Z 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, getUtility
21from waeup.kofa.interfaces import (IKofaUtils,
22    CLEARED, RETURNING, PAID, REGISTERED, VALIDATED)
23from waeup.kofa.utils.helpers import to_timezone
24from waeup.kofa.students.utils import trans
25from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
26from waeup.uniben.interfaces import MessageFactory as _
27
28class CustomStudentsUtils(NigeriaStudentsUtils):
29    """A collection of customized methods.
30
31    """
32
33    def getReturningData(self, student):
34        """ This method defines what happens after school fee payment
35        of returning students depending on the student's senate verdict.
36        """
37        prev_level = student['studycourse'].current_level
38        cur_verdict = student['studycourse'].current_verdict
39        if cur_verdict in ('A','B','L','M','N','Z',):
40            # Successful student
41            new_level = divmod(int(prev_level),100)[0]*100 + 100
42        elif cur_verdict == 'C':
43            # Student on probation
44            new_level = int(prev_level) + 10
45        else:
46            # Student is somehow in an undefined state.
47            # Level has to be set manually.
48            new_level = prev_level
49        new_session = student['studycourse'].current_session + 1
50        return new_session, new_level
51
52
53    def checkAccommodationRequirements(self, student, acc_details):
54        if acc_details.get('expired', False):
55            startdate = acc_details.get('startdate')
56            enddate = acc_details.get('enddate')
57            if startdate and enddate:
58                tz = getUtility(IKofaUtils).tzinfo
59                startdate = to_timezone(
60                    startdate, tz).strftime("%d/%m/%Y %H:%M:%S")
61                enddate = to_timezone(
62                    enddate, tz).strftime("%d/%m/%Y %H:%M:%S")
63                return _("Outside booking period: ${a} - ${b}",
64                         mapping = {'a': startdate, 'b': enddate})
65            else:
66                return _("Outside booking period.")
67        if student.current_mode != 'ug_ft':
68            return _("Only undergraduate full-time students are eligible to book accommodation.")
69        bt = acc_details.get('bt')
70        if not bt:
71            return _("Your data are incomplete.")
72        if not student.state in acc_details['allowed_states']:
73            return _("You are in the wrong registration state.")
74        if student['studycourse'].current_session != acc_details[
75            'booking_session']:
76            return _('Your current session does not '
77                     'match accommodation session.')
78        stage = bt.split('_')[2]
79        if stage not in ('fr', 'fi'):
80            return _("Only fresh and final year students are allowed to book accommodation.")
81
82        ####################################################################################
83        if stage == 'fi':
84            return _("Accommodation booking for final year students has not yet started.")
85        ####################################################################################
86
87
88        if stage != 'fr' and not student['studycourse'].previous_verdict in ('A', 'B'):
89            return _("Your are not eligible to book accommodation.")
90        if str(acc_details['booking_session']) in student['accommodation'].keys():
91            return _('You already booked a bed space in '
92                     'current accommodation session.')
93        return
94
95    def getAccommodationDetails(self, student):
96        """Determine the accommodation data of a student.
97        """
98        d = {}
99        d['error'] = u''
100        hostels = grok.getSite()['hostels']
101        d['booking_session'] = hostels.accommodation_session
102        d['allowed_states'] = hostels.accommodation_states
103        d['startdate'] = hostels.startdate
104        d['enddate'] = hostels.enddate
105        d['expired'] = hostels.expired
106        # Determine bed type
107        studycourse = student['studycourse']
108        certificate = getattr(studycourse,'certificate',None)
109        entry_session = studycourse.entry_session
110        current_level = studycourse.current_level
111        if None in (entry_session, current_level, certificate):
112            return d
113        end_level = certificate.end_level
114        if current_level == 10:
115            bt = 'pr'
116        elif entry_session == grok.getSite()['hostels'].accommodation_session:
117            bt = 'fr'
118        elif current_level >= end_level:
119            bt = 'fi'
120        else:
121            bt = 're'
122        if student.sex == 'f':
123            sex = 'female'
124        else:
125            sex = 'male'
126        special_handling = 'regular'
127        if student.faccode in ('MED', 'DEN'):
128            special_handling = 'clinical'
129        elif student.certcode in ('BARTMAS', 'MARTTHR', 'BARTFAA',
130                                  'BAEDFAA', 'BSCEDECHED'):
131            special_handling = 'ekenwan'
132        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
133        return d
134
135    def _paymentMade(self, student, session):
136        if len(student['payments']):
137            for ticket in student['payments'].values():
138                if ticket.p_state == 'paid' and \
139                    ticket.p_category == 'schoolfee' and \
140                    ticket.p_session == session:
141                    return True
142        return False
143
144    #def _hostelApplicationPaymentMade(self, student, session):
145    #    if len(student['payments']):
146    #        for ticket in student['payments'].values():
147    #            if ticket.p_state == 'paid' and \
148    #                ticket.p_category == 'hostel_application' and \
149    #                ticket.p_session == session:
150    #                return True
151    #    return False
152
153    def setPaymentDetails(self, category, student,
154            previous_session, previous_level):
155        """Create Payment object and set the payment data of a student for
156        the payment category specified.
157
158        """
159        p_item = u''
160        amount = 0.0
161        if previous_session:
162            if previous_session < student['studycourse'].entry_session:
163                return _('The previous session must not fall below '
164                         'your entry session.'), None
165            if category == 'schoolfee':
166                # School fee is always paid for the following session
167                if previous_session > student['studycourse'].current_session:
168                    return _('This is not a previous session.'), None
169            else:
170                if previous_session > student['studycourse'].current_session - 1:
171                    return _('This is not a previous session.'), None
172            p_session = previous_session
173            p_level = previous_level
174            p_current = False
175        else:
176            p_session = student['studycourse'].current_session
177            p_level = student['studycourse'].current_level
178            p_current = True
179        academic_session = self._getSessionConfiguration(p_session)
180        if academic_session == None:
181            return _(u'Session configuration object is not available.'), None
182        # Determine fee.
183        if category == 'transfer':
184            amount = academic_session.transfer_fee
185        elif category == 'transcript':
186            amount = academic_session.transcript_fee
187        elif category == 'gown':
188            amount = academic_session.gown_fee
189        elif category == 'bed_allocation':
190            p_item = self.getAccommodationDetails(student)['bt']
191            amount = academic_session.booking_fee
192            # Add student union dues
193            stage = self.getAccommodationDetails(student)['bt']
194            stage = stage.split('_')[2]
195
196
197            #####################################################
198            if stage == 'fi':
199                return _('Payment temporarily disabled.'), None
200            #####################################################
201
202
203            if stage == 'fr':
204                amount += 500.0
205            elif stage == 'fi' and student[
206                'studycourse'].previous_verdict in ('A', 'B'):
207                amount += 300.0
208            else:
209                amount = 0.0
210        elif category == 'hostel_maintenance':
211            amount = 0.0
212            bedticket = student['accommodation'].get(
213                str(student.current_session), None)
214            if bedticket:
215                p_item = bedticket.bed_coordinates
216                if bedticket.bed.__parent__.maint_fee > 0:
217                    amount = bedticket.bed.__parent__.maint_fee
218                else:
219                    # fallback
220                    amount = academic_session.maint_fee
221            else:
222                # Should not happen because this is already checked
223                # in the browser module, but anyway ...
224                portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
225                p_item = trans(_('no bed allocated'), portal_language)
226
227            #####################################
228            amount = 0.0        # disable all maintenance payments
229            #####################################
230
231        #elif category == 'hostel_application':
232        #    amount = 1000.0
233        #elif category.startswith('tempmaint'):
234        #    if not self._hostelApplicationPaymentMade(
235        #        student, student.current_session):
236        #        return _(
237        #            'You have not yet paid the hostel application fee.'), None
238        #    if category == 'tempmaint_1':
239        #        amount = 8150.0
240        #    elif category == 'tempmaint_2':
241        #        amount = 12650.0
242        #    elif category == 'tempmaint_3':
243        #        amount = 9650.0
244        elif category == 'clearance':
245            p_item = student.certcode
246            if p_item is None:
247                return _('Study course data are incomplete.'), None
248            if student.faccode == 'JUPEB':
249                return _('No payment required.'), None
250            if student.faccode == 'FCETA':
251                amount = 22500.0
252            elif p_item in ('BSCANA', 'BSCMBC', 'BMLS', 'BSCNUR', 'BSCPHS', 'BDS',
253                'MBBSMED', 'MBBSNDU'):
254                amount = 65000.0
255            elif p_item in ('BEDCET', 'BIOEDCET', 'CHMEDCET', 'ISEDCET',
256                'MTHEDCET', 'PHYEDCET', 'ITECET', 'AGREDCET', 'HEEDCET'):
257                amount = 22500.0
258            else:
259                amount = 45000.0
260        elif category == 'schoolfee':
261            try:
262                certificate = student['studycourse'].certificate
263                p_item = certificate.code
264            except (AttributeError, TypeError):
265                return _('Study course data are incomplete.'), None
266
267            #####################################################
268            #if student.faccode == 'JUPEB':
269            #    return _('Payment temporarily disabled.'), None
270            #####################################################
271
272
273            if previous_session:
274                # Students can pay for previous sessions in all workflow states.
275                # Fresh students are excluded by the update method of the
276                # PreviousPaymentAddFormPage.
277                if previous_session == student['studycourse'].entry_session:
278                    if student.is_foreigner:
279                        amount = getattr(certificate, 'school_fee_3', 0.0)
280                    else:
281                        amount = getattr(certificate, 'school_fee_1', 0.0)
282                else:
283                    if student.is_foreigner:
284                        amount = getattr(certificate, 'school_fee_4', 0.0)
285                    else:
286                        amount = getattr(certificate, 'school_fee_2', 0.0)
287            else:
288                if student.state == CLEARED:
289                    if student.is_foreigner:
290                        amount = getattr(certificate, 'school_fee_3', 0.0)
291                    else:
292                        amount = getattr(certificate, 'school_fee_1', 0.0)
293                elif student.state in (PAID, REGISTERED, VALIDATED):
294                    p_session += 1
295                    # We don't know which level the student is paying for.
296                    p_level = None
297                    academic_session = self._getSessionConfiguration(p_session)
298                    if academic_session == None:
299                        return _(u'Session configuration object is not available.'), None
300
301                    # Students are only allowed to pay for the next session
302                    # if current session payment
303                    # has really been made, i.e. payment object exists.
304                    #if not self._paymentMade(
305                    #    student, student.current_session):
306                    #    return _('You have not yet paid your current/active' +
307                    #             ' session. Please use the previous session' +
308                    #             ' payment form first.'), None
309
310                    if student.is_foreigner:
311                        amount = getattr(certificate, 'school_fee_4', 0.0)
312                    else:
313                        amount = getattr(certificate, 'school_fee_2', 0.0)
314                elif student.state == RETURNING:
315                    # In case of returning school fee payment the payment session
316                    # and level contain the values of the session the student
317                    # has paid for.
318                    p_session, p_level = self.getReturningData(student)
319                    academic_session = self._getSessionConfiguration(p_session)
320                    if academic_session == None:
321                        return _(u'Session configuration object is not available.'), None
322
323                    # Students are only allowed to pay for the next session
324                    # if current session payment has really been made,
325                    # i.e. payment object exists and is paid.
326                    #if not self._paymentMade(
327                    #    student, student.current_session):
328                    #    return _('You have not yet paid your current/active' +
329                    #             ' session. Please use the previous session' +
330                    #             ' payment form first.'), None
331
332                    if student.is_foreigner:
333                        amount = getattr(certificate, 'school_fee_4', 0.0)
334                    else:
335                        amount = getattr(certificate, 'school_fee_2', 0.0)
336            # Give 50% school fee discount to staff members.
337            if student.is_staff:
338                amount /= 2
339        if amount in (0.0, None):
340            return _('Amount could not be determined.'), None
341        # Add session specific penalty fee.
342        if category == 'schoolfee' and student.is_postgrad:
343            amount += academic_session.penalty_pg
344        elif category == 'schoolfee':
345            amount += academic_session.penalty_ug
346        if category.startswith('tempmaint'):
347            p_item = getUtility(IKofaUtils).PAYMENT_CATEGORIES[category]
348            p_item = unicode(p_item)
349            # Now we change the category because tempmaint payments
350            # will be obsolete when Uniben returns to Kofa bed allocation.
351            category = 'hostel_maintenance'
352        # Create ticket.
353        if self.samePaymentMade(student, category, p_item, p_session):
354            return _('This type of payment has already been made.'), None
355        if self._isPaymentDisabled(p_session, category, student):
356            return _('Payment temporarily disabled.'), None
357        payment = createObject(u'waeup.StudentOnlinePayment')
358        timestamp = ("%d" % int(time()*10000))[1:]
359        payment.p_id = "p%s" % timestamp
360        payment.p_category = category
361        payment.p_item = p_item
362        payment.p_session = p_session
363        payment.p_level = p_level
364        payment.p_current = p_current
365        payment.amount_auth = amount
366        return None, payment
367
368    def maxCredits(self, studylevel):
369        """Return maximum credits.
370
371        """
372        studycourse = studylevel.__parent__
373        certificate = getattr(studycourse,'certificate', None)
374        current_level = studycourse.current_level
375        if None in (current_level, certificate):
376            return 0
377        end_level = certificate.end_level
378        if current_level >= end_level:
379            return 51
380        return 50
381
382    def clearance_disabled_message(self, student):
383        if student.is_postgrad:
384            return None
385        try:
386            session_config = grok.getSite()[
387                'configuration'][str(student.current_session)]
388        except KeyError:
389            return _('Session configuration object is not available.')
390        if not session_config.clearance_enabled:
391            return _('Clearance is disabled for this session.')
392        return None
393
394    def selectBed(self, available_beds):
395        """Select a bed from a list of available beds.
396        Beds are sorted by the sort id of the hostel and the bed number.
397        The first bed found in this sorted list is taken.
398        """
399        sorted_beds = sorted(available_beds,
400            key=lambda bed: 1000 * bed.__parent__.sort_id + bed.bed_number)
401        return sorted_beds[0]
402
403    # Uniben prefix
404    STUDENT_ID_PREFIX = u'B'
Note: See TracBrowser for help on using the repository browser.