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

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

Reconfigure payments according to ticket #129. Some tests are still missing. Do not upgrade!

  • Property svn:keywords set to Id
File size: 10.5 KB
Line 
1## $Id: utils.py 13400 2015-11-06 18:29: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##
18import grok
19from time import time
20from zope.component import createObject
21from waeup.kofa.interfaces import (
22    ADMITTED, CLEARED, RETURNING, PAID, academic_sessions_vocab)
23from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
24from waeup.kofa.accesscodes import create_accesscode
25from waeup.kofa.students.utils import trans
26from waeup.aaue.interfaces import MessageFactory as _
27
28class CustomStudentsUtils(NigeriaStudentsUtils):
29    """A collection of customized methods.
30
31    """
32
33    PORTRAIT_CHANGE_STATES = (ADMITTED, RETURNING)
34
35    gpa_boundaries = ((1, 'FRNS'),
36                      (1.5, 'Pass'),
37                      (2.4, '3rd Class Honours'),
38                      (3.5, '2nd Class Honours Lower Division'),
39                      (4.5, '2nd Class Honours Upper Division'),
40                      (5, '1st Class Honours'))
41
42    def increaseMatricInteger(self, student):
43        """Increase counter for matric numbers.
44        This counter can be a centrally stored attribute or an attribute of
45        faculties, departments or certificates. In the base package the counter
46        is as an attribute of the site configuration container.
47        """
48        if student.current_mode in ('ug_pt', 'de_pt'):
49            grok.getSite()['configuration'].next_matric_integer += 1
50            return
51        grok.getSite()['configuration'].next_matric_integer_2 += 1
52        return
53
54    def constructMatricNumber(self, student):
55        faccode = student.faccode
56        depcode = student.depcode
57        year = unicode(student.entry_session)[2:]
58        if not student.state in (PAID, ) or not student.is_fresh or \
59            student.current_mode == 'found':
60            return _('Matriculation number cannot be set.'), None
61        if student.current_mode in ('ug_pt', 'de_pt'):
62            next_integer = grok.getSite()['configuration'].next_matric_integer
63            if next_integer == 0:
64                return _('Matriculation number cannot be set.'), None
65            return None, "PTP/%s/%s/%s/%05d" % (
66                faccode, depcode, year, next_integer)
67        next_integer = grok.getSite()['configuration'].next_matric_integer_2
68        if next_integer == 0:
69            return _('Matriculation number cannot be set.'), None
70        if student.faccode in ('FBM', 'FCS'):
71            return None, "CMS/%s/%s/%s/%05d" % (
72                faccode, depcode, year, next_integer)
73        return None, "%s/%s/%s/%05d" % (faccode, depcode, year, next_integer)
74
75    def getReturningData(self, student):
76        """ This method defines what happens after school fee payment
77        of returning students depending on the student's senate verdict.
78        """
79        prev_level = student['studycourse'].current_level
80        cur_verdict = student['studycourse'].current_verdict
81        if cur_verdict in ('A','B','L','M','N','Z',):
82            # Successful student
83            new_level = divmod(int(prev_level),100)[0]*100 + 100
84        elif cur_verdict == 'C':
85            # Student on probation
86            new_level = int(prev_level) + 10
87        else:
88            # Student is somehow in an undefined state.
89            # Level has to be set manually.
90            new_level = prev_level
91        new_session = student['studycourse'].current_session + 1
92        return new_session, new_level
93
94    def setPaymentDetails(self, category, student,
95            previous_session=None, previous_level=None):
96        """Create Payment object and set the payment data of a student for
97        the payment category specified.
98
99        """
100        details = {}
101        p_item = u''
102        amount = 0.0
103        error = u''
104        if previous_session:
105            return _('Previous session payment not yet implemented.'), None
106        p_session = student['studycourse'].current_session
107        p_level = student['studycourse'].current_level
108        p_current = True
109        academic_session = self._getSessionConfiguration(p_session)
110        if academic_session == None:
111            return _(u'Session configuration object is not available.'), None
112        # Determine fee.
113        if category == 'transfer':
114            amount = academic_session.transfer_fee
115        elif category == 'transcript':
116            amount = academic_session.transcript_fee
117        elif category == 'gown':
118            amount = academic_session.gown_fee
119        elif category == 'bed_allocation':
120            amount = academic_session.booking_fee
121        elif category == 'hostel_maintenance':
122            amount = academic_session.maint_fee
123        elif category == 'welfare':
124            amount = academic_session.welfare_fee
125        elif category == 'union':
126            amount = academic_session.union_fee
127        elif category == 'lapel':
128            amount = academic_session.lapel_fee
129        elif category == 'matric_gown':
130            amount = academic_session.matric_gown_fee
131        elif category == 'concessional':
132            amount = academic_session.concession_fee
133        elif category == 'medical':
134            amount = academic_session.medical_fee
135        elif category.startswith('clearance'):
136            if student.faccode == 'FP':
137                amount = academic_session.clearance_fee_fp
138            elif student.current_mode.endswith('_pt'):
139                amount = academic_session.clearance_fee_pt
140            elif student.faccode in ('FBM', 'FCS'):
141                amount = academic_session.clearance_fee_med
142            else:
143                amount = academic_session.clearance_fee
144            p_item = student['studycourse'].certificate.code
145            # Add Matric Gown Fee and Lapel Fee
146            if category == 'clearance_incl':
147                if amount is None:
148                    # Otherwise we can't add somtehing
149                    amount = 0.0
150                amount += academic_session.matric_gown_fee + academic_session.lapel_fee
151        elif category == 'late_registration':
152            amount = academic_session.late_registration_fee
153        elif category.startswith('schoolfee'):
154            try:
155                certificate = student['studycourse'].certificate
156                p_item = certificate.code
157            except (AttributeError, TypeError):
158                return _('Study course data are incomplete.'), None
159            if student.state == CLEARED:
160                if student.is_foreigner:
161                    amount = getattr(certificate, 'school_fee_3', 0.0)
162                else:
163                    amount = getattr(certificate, 'school_fee_1', 0.0)
164            elif student.state == RETURNING:
165                # In case of returning school fee payment the payment session
166                # and level contain the values of the session the student
167                # has paid for.
168                p_session, p_level = self.getReturningData(student)
169                try:
170                    academic_session = grok.getSite()[
171                        'configuration'][str(p_session)]
172                except KeyError:
173                    return _(u'Session configuration object is not available.'), None
174                if student.is_foreigner:
175                    amount = getattr(certificate, 'school_fee_4', 0.0)
176                else:
177                    amount = getattr(certificate, 'school_fee_2', 0.0)
178            else:
179                return _('Wrong state.'), None
180            # Add Student Union Fee and Welfare Assurance
181            if category == 'schoolfee_incl':
182                if amount is None:
183                    # Otherwise we can't add somtehing
184                    amount = 0.0
185                amount += academic_session.welfare_fee + academic_session.union_fee
186        if amount in (0.0, None):
187            return _(u'Amount could not be determined.'), None
188        # Add session specific penalty fee.
189        if category == 'schoolfee' and student.is_postgrad:
190            amount += academic_session.penalty_pg
191        elif category == 'schoolfee':
192            amount += academic_session.penalty_ug
193        # Create ticket.
194        for key in student['payments'].keys():
195            ticket = student['payments'][key]
196            if ticket.p_state == 'paid' and\
197               ticket.p_category == category and \
198               ticket.p_item == p_item and \
199               ticket.p_session == p_session:
200                  return _('This type of payment has already been made.'), None
201        if self._isPaymentDisabled(p_session, category, student):
202            return _('Payment temporarily disabled.'), None
203        payment = createObject(u'waeup.StudentOnlinePayment')
204        timestamp = ("%d" % int(time()*10000))[1:]
205        payment.p_id = "p%s" % timestamp
206        payment.p_category = category
207        payment.p_item = p_item
208        payment.p_session = p_session
209        payment.p_level = p_level
210        payment.p_current = p_current
211        payment.amount_auth = amount
212        return None, payment
213
214    def _admissionText(self, student, portal_language):
215        inst_name = grok.getSite()['configuration'].name
216        entry_session = student['studycourse'].entry_session
217        entry_session = academic_sessions_vocab.getTerm(entry_session).title
218        text = trans(_(
219            'This is to inform you that you have been offered provisional'
220            ' admission into ${a} for the ${b} academic session as follows:',
221            mapping = {'a': inst_name, 'b': entry_session}),
222            portal_language)
223        return text
224
225    def maxCredits(self, studylevel):
226        """Return maximum credits.
227
228        """
229        return 48
230
231    def getBedCoordinates(self, bedticket):
232        """Return descriptive bed coordinates.
233        This method can be used to customize the `display_coordinates`
234        property method in order to  display a
235        customary description of the bed space.
236        """
237        bc = bedticket.bed_coordinates.split(',')
238        if len(bc) == 4:
239            return bc[0]
240        return bedticket.bed_coordinates
241
242    # AAUE prefix
243    STUDENT_ID_PREFIX = u'E'
Note: See TracBrowser for help on using the repository browser.