source: main/waeup.aaue/trunk/src/waeup/aaue/interswitch/browser.py @ 17432

Last change on this file since 17432 was 17431, checked in by Henrik Bettermann, 17 months ago

Rewrite payment configuration.

  • Property svn:executable set to *
File size: 16.3 KB
Line 
1    # -*- coding: utf-8 -*-
2## $Id: browser.py 17429 2023-06-05 04:34:30Z henrik $
3##
4## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
5## This program is free software; you can redistribute it and/or modify
6## it under the terms of the GNU General Public License as published by
7## the Free Software Foundation; either version 2 of the License, or
8## (at your option) any later version.
9##
10## This program is distributed in the hope that it will be useful,
11## but WITHOUT ANY WARRANTY; without even the implied warranty ofself.context.amount_auth
12## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13## GNU General Public License for more details.
14##
15## You should have received a copy of the GNU General Public License
16## along with this program; if not, write to the Free Software
17## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18##
19import httplib
20import hashlib
21import grok
22import os
23import csv
24from xml.dom import minidom
25from zope.interface import Interface
26from zope.component import queryAdapter
27from waeup.kofa.interfaces import CLEARED
28from kofacustom.nigeria.interswitch.browser import (
29    InterswitchPaymentRequestWebservicePageStudent,
30    InterswitchPaymentRequestWebservicePageApplicant,
31    InterswitchPaymentVerifyWebservicePageApplicant,
32    InterswitchPaymentVerifyWebservicePageStudent,
33    InterswitchPageStudent, InterswitchPageApplicant,
34    module_activated,
35    )
36from waeup.aaue.students.interfaces import ICustomStudentOnlinePayment
37from waeup.aaue.applicants.interfaces import ICustomApplicantOnlinePayment
38from waeup.aaue.interfaces import MessageFactory as _
39
40PRODUCT_ID = '5845'
41SITE_NAME = 'aaue.waeup.org'
42PROVIDER_ACCT = '0200244434'
43PROVIDER_BANK_ID = '11'
44PROVIDER_ITEM_NAME = 'WAeAC'
45INSTITUTION_NAME = 'AAU Ekpoma'
46CURRENCY = '566'
47GATEWAY_AMT = 200.0
48POST_ACTION = 'https://webpay.interswitchng.com/paydirect/pay'
49
50HOST = 'webpay.interswitchng.com'
51URL = '/paydirect/api/v1/gettransaction.json'
52HTTPS = True
53MAC = '9718FA00B0F5070B388A9896ADCED9B2FB02D30F71E12E68BDADC63F6852A3496FF97D8A0F9DA9F753B911A49BB09BB87B55FD02046BD325C74C46C0123CF023'
54
55httplib.HTTPSConnection.debuglevel = 0
56
57BANK_ACCOUNTS = {
58    'edohis':   ('1222577132', '117', 'Edo State Health Insurance'),
59    'union':    ('1019763348', '7', 'Student Union'),
60    'sport':    ('1021941220', '7', 'Sport Development'),
61    'access':   ('1012688013', '123', 'Access Card'),
62    'notebook': ('4011210501', '51', 'Branded Notebook'),
63    'library':  ('2000122995', '8', 'Library Development'),
64    'fac1':     ('1022438743', '7', 'Faculty Fee'),
65    'fac2':     ('2000249757', '8', 'Faculty Fee'),
66    'fac3':     ('1012678566', '123', 'Faculty Fee'),
67    'acceptance': ('2000249757', '8', 'Acceptance Fee'),
68    'matricgown': ('2000249757', '8', 'Matriculation Gown Fee'),
69    'lapel':      ('2000249757', '8', 'Lapel Fee'),
70    }
71
72schoolfees_path = os.path.join(
73    os.path.dirname(__file__), '../students/schoolfees.csv')
74reader = csv.DictReader(open(schoolfees_path, 'rb'))
75SCHOOLFEES = {item['code']:item for item in reader}
76
77acceptancefees_path = os.path.join(
78    os.path.dirname(__file__), '../students/acceptancefees.csv')
79reader = csv.DictReader(open(acceptancefees_path, 'rb'))
80ACCEPTANCEFEES = {item['code']:item for item in reader}
81
82class CustomInterswitchPageApplicant(InterswitchPageApplicant):
83    """ View which sends a POST request to the Interswitch
84    CollegePAY payment gateway.
85
86    So far only PT application has been configured.
87    """
88    grok.context(ICustomApplicantOnlinePayment)
89    action = POST_ACTION
90    site_name = SITE_NAME
91    currency = CURRENCY
92    provider_bank_id = PROVIDER_BANK_ID
93    provider_acct = PROVIDER_ACCT
94    pay_item_id = '101'
95
96    def update(self):
97        if not module_activated(
98            self.context.__parent__.__parent__.year, self.context):
99            self.flash(_('Forbidden'), type='danger')
100            self.redirect(self.url(self.context, '@@index'))
101            return
102        error = self.init_update()
103        if error:
104            self.flash(error, type='danger')
105            self.redirect(self.url(self.context, '@@index'))
106            return
107        # Already now it becomes an Interswitch payment. We set the net amount
108        # and add the gateway amount.
109        if not self.context.r_company:
110            self.context.net_amt = self.context.amount_auth
111            self.context.amount_auth += GATEWAY_AMT
112            self.context.gateway_amt = GATEWAY_AMT
113            self.context.r_company = u'interswitch'
114        xmldict = {}
115        provider_amt = 2000.0
116        if self.applicant.applicant_id.startswith('trans'):
117            provider_amt = 3000.0
118        xmldict['institution_acct'] = '00000000'
119        xmldict['institution_bank_id'] = '00'
120        xmldict['detail_ref'] = self.context.p_id
121        xmldict['provider_amt'] = 100 * provider_amt
122        xmldict['provider_acct'] = PROVIDER_ACCT
123        xmldict['provider_bank_id'] = PROVIDER_BANK_ID
124        xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
125        xmldict['institution_item_name'] = self.context.category
126        xmldict['institution_name'] = INSTITUTION_NAME
127        xmldict['institution_amt'] = 100 * self.context.net_amt
128        if not self.context.provider_amt:
129            self.context.provider_amt = provider_amt
130            self.context.amount_auth += provider_amt
131        xmltext = """<payment_item_detail>
132<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s">
133<item_detail item_id="1" item_name="%(institution_item_name)s" item_amt="%(institution_amt)d" bank_id="%(institution_bank_id)s" acct_num="%(institution_acct)s" />
134<item_detail item_id="2" item_name="%(provider_item_name)s" item_amt="%(provider_amt)d" bank_id="%(provider_bank_id)s" acct_num="%(provider_acct)s" />
135</item_details>
136</payment_item_detail>""" % xmldict
137        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
138        xmlitems = ''
139        xmldoc = minidom.parseString(xmltext)
140        itemlist = xmldoc.getElementsByTagName('item_detail')
141        for s in itemlist:
142            xmlitems += "%s: %s, N%s, %s (%s)  " % (
143                s.attributes['item_id'].value,
144                s.attributes['item_name'].value,
145                int(s.attributes['item_amt'].value)/100,
146                s.attributes['acct_num'].value,
147                s.attributes['bank_id'].value,
148                )
149        self.context.p_split_data = xmlitems
150        self.amount_auth = int(100 * self.context.amount_auth)
151        hashargs = (
152            self.context.p_id +
153            PRODUCT_ID +
154            self.pay_item_id +
155            str(int(self.amount_auth)) +
156            self.site_redirect_url +
157            MAC)
158        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
159        return
160
161class CustomInterswitchPageStudent(InterswitchPageStudent):
162    """ View which sends a POST request to the Interswitch
163    CollegePAY payment gateway.
164    """
165    grok.context(ICustomStudentOnlinePayment)
166    action = POST_ACTION
167    site_name = SITE_NAME
168    currency = CURRENCY
169    pay_item_id = '101'
170
171    def update(self):
172        if not module_activated(
173            self.context.student.current_session, self.context):
174            self.flash(_('Forbidden'), type='danger')
175            self.redirect(self.url(self.context, '@@index'))
176            return
177        error = self.init_update()
178        if error:
179            self.flash(error, type='danger')
180            self.redirect(self.url(self.context, '@@index'))
181            return
182        category = self.context.p_category
183        # Already now it becomes an Interswitch payment. We set the net amount
184        # and add the gateway amount.
185        if not self.context.r_company:
186            self.context.net_amt = self.context.amount_auth
187            self.context.amount_auth += GATEWAY_AMT
188            self.context.gateway_amt = GATEWAY_AMT
189            self.context.r_company = u'interswitch'
190        student = self.student
191        xmldict = self.xmldict
192        # Provider data
193        xmldict['detail_ref'] = self.context.p_id
194        xmldict['provider_acct'] = PROVIDER_ACCT
195        xmldict['provider_bank_id'] = PROVIDER_BANK_ID
196        xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
197        # Institution data
198        xmldict['institution_acct'] = '00000000'
199        xmldict['institution_bank_id'] = '00'
200        provider_amt = 0.0
201        if category.startswith('clearance'):
202            provider_amt = 1500.0
203        elif category.startswith('hostel_maintenance'):
204            provider_amt = 1000.0
205        elif category in ('schoolfee', 'schoolfee_1', 'schoolfee_incl'):
206            provider_amt = 2500.0
207        xmldict['provider_amt'] = 100 * provider_amt
208        xmldict['institution_item_name'] = self.context.category
209        xmldict['institution_name'] = INSTITUTION_NAME
210        xmldict['institution_amt'] = 100 * self.context.net_amt
211        if not self.context.provider_amt:
212            self.context.provider_amt = provider_amt
213            self.context.amount_auth += provider_amt
214        xmltext = ''
215
216        # School fee
217        if category.startswith('schoolfee'):
218            # collect additional fees
219            if self.context.p_category in ('schoolfee_1', 'schoolfee_incl'):
220                xmltext = """<payment_item_detail>
221<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">""" % xmldict
222                item_id = 1
223                for item in SCHOOLFEES[student.certcode].items():
224                    try:
225                        item_amt = 100 * int(item[1])
226                        if self.context.p_category == 'schoolfee_1' and item[0] == 'tuition':
227                            item_amt /= 2
228                        acct_num = ''
229                        bank_id = ''
230                        item_name = ''
231                        # Find appropriate bank
232                        try:
233                            bank = BANK_ACCOUNTS[item[0]]
234                        except: # transfer to faculty account
235                            if student.faccode in ('FAG', 'FAT', 'FBM', 'FMLS', 'fac1'):
236                                bank = BANK_ACCOUNTS['fac1']
237                            elif student.faccode in ('FCS', 'FED', 'FES', 'FET'):
238                                bank = BANK_ACCOUNTS['fac2']
239                            elif student.faccode in ('FLS', 'FLW', 'FMS', 'FPS', 'FSS'):
240                                bank = BANK_ACCOUNTS['fac3']
241                        acct_num = bank[0]
242                        bank_id = bank[1]
243                        item_name = "%s (%s)" % (bank[2], item[0])
244                        xmltext += """
245<item_detail item_id="%s" item_name="%s" item_amt="%d" bank_id="%s" acct_num="%s" />""" % (item_id, item_name, item_amt, bank_id, acct_num)
246                        item_id += 1
247                    except:
248                        pass
249                xmldict['item_id'] = item_id
250                xmltext += """
251<item_detail item_id="%(item_id)d" item_name="%(provider_item_name)s" item_amt="%(provider_amt)d" bank_id="%(provider_bank_id)s" acct_num="%(provider_acct)s" />
252</item_details>
253</payment_item_detail>""" % xmldict
254            # no additional charges, determine faculty bank only
255            else:
256                if student.faccode in ('FAG', 'FAT', 'FBM', 'FMLS', 'fac1'):
257                    bank = BANK_ACCOUNTS['fac1']
258                elif student.faccode in ('FCS', 'FED', 'FES', 'FET'):
259                    bank = BANK_ACCOUNTS['fac2']
260                elif student.faccode in ('FLS', 'FLW', 'FMS', 'FPS', 'FSS'):
261                    bank = BANK_ACCOUNTS['fac3']
262                xmldict['institution_acct'] = bank[0]
263                xmldict['institution_bank_id'] = bank[1]
264
265
266        # Clearance (acceptance) fee
267
268        if category.startswith('clearance'):
269            # collect additional fees
270            if self.context.p_category == 'clearance_incl':
271                xmltext = """<payment_item_detail>
272<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">""" % xmldict
273                item_id = 1
274                for item in ACCEPTANCEFEES[student.certcode].items():
275                    try:
276                        item_amt = 100 * int(item[1])
277                        bank = BANK_ACCOUNTS[item[0]]
278                        acct_num = bank[0]
279                        bank_id = bank[1]
280                        item_name = "%s (%s)" % (bank[2], item[0])
281                        xmltext += """
282<item_detail item_id="%s" item_name="%s" item_amt="%d" bank_id="%s" acct_num="%s" />""" % (item_id, item_name, item_amt, bank_id, acct_num)
283                        item_id += 1
284                    except:
285                        pass
286                xmldict['item_id'] = item_id
287                xmltext += """
288<item_detail item_id="%(item_id)d" item_name="%(provider_item_name)s" item_amt="%(provider_amt)d" bank_id="%(provider_bank_id)s" acct_num="%(provider_acct)s" />
289</item_details>
290</payment_item_detail>""" % xmldict
291            # no additional charges, determine faculty bank only
292            else:
293                bank = BANK_ACCOUNTS['acceptance']
294                xmldict['institution_acct'] = bank[0]
295                xmldict['institution_bank_id'] = bank[1]
296
297        # Other fees
298
299
300        if not xmltext and provider_amt == 0:
301            xmltext = """<payment_item_detail>
302<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
303<item_detail item_id="1" item_name="%(institution_item_name)s" item_amt="%(institution_amt)d" bank_id="%(institution_bank_id)s" acct_num="%(institution_acct)s" />
304</item_details>
305</payment_item_detail>""" % xmldict
306        elif not xmltext:
307            xmltext = """<payment_item_detail>
308<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
309<item_detail item_id="1" item_name="%(institution_item_name)s" item_amt="%(institution_amt)d" bank_id="%(institution_bank_id)s" acct_num="%(institution_acct)s" />
310<item_detail item_id="2" item_name="%(provider_item_name)s" item_amt="%(provider_amt)d" bank_id="%(provider_bank_id)s" acct_num="%(provider_acct)s" />
311</item_details>
312</payment_item_detail>""" % xmldict
313        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
314        xmlitems = ''
315        xmldoc = minidom.parseString(xmltext)
316        itemlist = xmldoc.getElementsByTagName('item_detail')
317        for s in itemlist:
318            xmlitems += "%s: %s, %s %s, %s (%s)  " % (
319                s.attributes['item_id'].value,
320                s.attributes['item_name'].value,
321                u'\u20a6',
322                int(s.attributes['item_amt'].value)/100,
323                s.attributes['acct_num'].value,
324                s.attributes['bank_id'].value,
325                )
326        self.context.p_split_data = xmlitems
327        self.context.provider_amt = provider_amt
328        self.amount_auth = int(100 * self.context.amount_auth)
329        hashargs = (
330            self.context.p_id +
331            PRODUCT_ID +
332            self.pay_item_id +
333            str(int(self.amount_auth)) +
334            self.site_redirect_url +
335            MAC)
336        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
337        return
338
339
340class CustomInterswitchPaymentRequestWebservicePageApplicant(
341    InterswitchPaymentRequestWebservicePageApplicant):
342    """Request webservice view for the CollegePAY gateway
343    """
344    grok.context(ICustomApplicantOnlinePayment)
345    gateway_host = HOST
346    gateway_url = URL
347    https = HTTPS
348
349class CustomInterswitchPaymentVerifyWebservicePageApplicant(
350    InterswitchPaymentVerifyWebservicePageApplicant):
351    """Payment verify view for the CollegePAY gateway
352    """
353    grok.context(ICustomApplicantOnlinePayment)
354    gateway_host = HOST
355    gateway_url = URL
356    https = HTTPS
357    mac = MAC
358    product_id = PRODUCT_ID
359
360class CustomInterswitchPaymentRequestWebservicePageStudent(
361    InterswitchPaymentRequestWebservicePageStudent):
362    """Request webservice view for the CollegePAY gateway
363    """
364    grok.context(ICustomStudentOnlinePayment)
365    gateway_host = HOST
366    gateway_url = URL
367    https = HTTPS
368    mac = MAC
369    product_id = PRODUCT_ID
370
371class CustomInterswitchPaymentVerifyWebservicePageStudent(
372    InterswitchPaymentVerifyWebservicePageStudent):
373    """Payment verify view for the CollegePAY gateway
374    """
375    grok.context(ICustomStudentOnlinePayment)
376    gateway_host = HOST
377    gateway_url = URL
378    https = HTTPS
379    mac = MAC
380    product_id = PRODUCT_ID
Note: See TracBrowser for help on using the repository browser.