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

Last change on this file since 17433 was 17433, checked in by Henrik Bettermann, 19 months ago

Add product_id.

  • Property svn:executable set to *
File size: 16.4 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    product_id = PRODUCT_ID
96
97    def update(self):
98        if not module_activated(
99            self.context.__parent__.__parent__.year, self.context):
100            self.flash(_('Forbidden'), type='danger')
101            self.redirect(self.url(self.context, '@@index'))
102            return
103        error = self.init_update()
104        if error:
105            self.flash(error, type='danger')
106            self.redirect(self.url(self.context, '@@index'))
107            return
108        # Already now it becomes an Interswitch payment. We set the net amount
109        # and add the gateway amount.
110        if not self.context.r_company:
111            self.context.net_amt = self.context.amount_auth
112            self.context.amount_auth += GATEWAY_AMT
113            self.context.gateway_amt = GATEWAY_AMT
114            self.context.r_company = u'interswitch'
115        xmldict = {}
116        provider_amt = 2000.0
117        if self.applicant.applicant_id.startswith('trans'):
118            provider_amt = 3000.0
119        xmldict['institution_acct'] = '00000000'
120        xmldict['institution_bank_id'] = '00'
121        xmldict['detail_ref'] = self.context.p_id
122        xmldict['provider_amt'] = 100 * provider_amt
123        xmldict['provider_acct'] = PROVIDER_ACCT
124        xmldict['provider_bank_id'] = PROVIDER_BANK_ID
125        xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
126        xmldict['institution_item_name'] = self.context.category
127        xmldict['institution_name'] = INSTITUTION_NAME
128        xmldict['institution_amt'] = 100 * self.context.net_amt
129        if not self.context.provider_amt:
130            self.context.provider_amt = provider_amt
131            self.context.amount_auth += provider_amt
132        xmltext = """<payment_item_detail>
133<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s">
134<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" />
135<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" />
136</item_details>
137</payment_item_detail>""" % xmldict
138        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
139        xmlitems = ''
140        xmldoc = minidom.parseString(xmltext)
141        itemlist = xmldoc.getElementsByTagName('item_detail')
142        for s in itemlist:
143            xmlitems += "%s: %s, N%s, %s (%s)  " % (
144                s.attributes['item_id'].value,
145                s.attributes['item_name'].value,
146                int(s.attributes['item_amt'].value)/100,
147                s.attributes['acct_num'].value,
148                s.attributes['bank_id'].value,
149                )
150        self.context.p_split_data = xmlitems
151        self.amount_auth = int(100 * self.context.amount_auth)
152        hashargs = (
153            self.context.p_id +
154            PRODUCT_ID +
155            self.pay_item_id +
156            str(int(self.amount_auth)) +
157            self.site_redirect_url +
158            MAC)
159        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
160        return
161
162class CustomInterswitchPageStudent(InterswitchPageStudent):
163    """ View which sends a POST request to the Interswitch
164    CollegePAY payment gateway.
165    """
166    grok.context(ICustomStudentOnlinePayment)
167    action = POST_ACTION
168    site_name = SITE_NAME
169    currency = CURRENCY
170    pay_item_id = '101'
171    product_id = PRODUCT_ID
172
173    def update(self):
174        if not module_activated(
175            self.context.student.current_session, self.context):
176            self.flash(_('Forbidden'), type='danger')
177            self.redirect(self.url(self.context, '@@index'))
178            return
179        error = self.init_update()
180        if error:
181            self.flash(error, type='danger')
182            self.redirect(self.url(self.context, '@@index'))
183            return
184        category = self.context.p_category
185        # Already now it becomes an Interswitch payment. We set the net amount
186        # and add the gateway amount.
187        if not self.context.r_company:
188            self.context.net_amt = self.context.amount_auth
189            self.context.amount_auth += GATEWAY_AMT
190            self.context.gateway_amt = GATEWAY_AMT
191            self.context.r_company = u'interswitch'
192        student = self.student
193        xmldict = self.xmldict
194        # Provider data
195        xmldict['detail_ref'] = self.context.p_id
196        xmldict['provider_acct'] = PROVIDER_ACCT
197        xmldict['provider_bank_id'] = PROVIDER_BANK_ID
198        xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
199        # Institution data
200        xmldict['institution_acct'] = '00000000'
201        xmldict['institution_bank_id'] = '00'
202        provider_amt = 0.0
203        if category.startswith('clearance'):
204            provider_amt = 1500.0
205        elif category.startswith('hostel_maintenance'):
206            provider_amt = 1000.0
207        elif category in ('schoolfee', 'schoolfee_1', 'schoolfee_incl'):
208            provider_amt = 2500.0
209        xmldict['provider_amt'] = 100 * provider_amt
210        xmldict['institution_item_name'] = self.context.category
211        xmldict['institution_name'] = INSTITUTION_NAME
212        xmldict['institution_amt'] = 100 * self.context.net_amt
213        if not self.context.provider_amt:
214            self.context.provider_amt = provider_amt
215            self.context.amount_auth += provider_amt
216        xmltext = ''
217
218        # School fee
219        if category.startswith('schoolfee'):
220            # collect additional fees
221            if self.context.p_category in ('schoolfee_1', 'schoolfee_incl'):
222                xmltext = """<payment_item_detail>
223<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">""" % xmldict
224                item_id = 1
225                for item in SCHOOLFEES[student.certcode].items():
226                    try:
227                        item_amt = 100 * int(item[1])
228                        if self.context.p_category == 'schoolfee_1' and item[0] == 'tuition':
229                            item_amt /= 2
230                        acct_num = ''
231                        bank_id = ''
232                        item_name = ''
233                        # Find appropriate bank
234                        try:
235                            bank = BANK_ACCOUNTS[item[0]]
236                        except: # transfer to faculty account
237                            if student.faccode in ('FAG', 'FAT', 'FBM', 'FMLS', 'fac1'):
238                                bank = BANK_ACCOUNTS['fac1']
239                            elif student.faccode in ('FCS', 'FED', 'FES', 'FET'):
240                                bank = BANK_ACCOUNTS['fac2']
241                            elif student.faccode in ('FLS', 'FLW', 'FMS', 'FPS', 'FSS'):
242                                bank = BANK_ACCOUNTS['fac3']
243                        acct_num = bank[0]
244                        bank_id = bank[1]
245                        item_name = "%s (%s)" % (bank[2], item[0])
246                        xmltext += """
247<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)
248                        item_id += 1
249                    except:
250                        pass
251                xmldict['item_id'] = item_id
252                xmltext += """
253<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" />
254</item_details>
255</payment_item_detail>""" % xmldict
256            # no additional charges, determine faculty bank only
257            else:
258                if student.faccode in ('FAG', 'FAT', 'FBM', 'FMLS', 'fac1'):
259                    bank = BANK_ACCOUNTS['fac1']
260                elif student.faccode in ('FCS', 'FED', 'FES', 'FET'):
261                    bank = BANK_ACCOUNTS['fac2']
262                elif student.faccode in ('FLS', 'FLW', 'FMS', 'FPS', 'FSS'):
263                    bank = BANK_ACCOUNTS['fac3']
264                xmldict['institution_acct'] = bank[0]
265                xmldict['institution_bank_id'] = bank[1]
266
267
268        # Clearance (acceptance) fee
269
270        if category.startswith('clearance'):
271            # collect additional fees
272            if self.context.p_category == 'clearance_incl':
273                xmltext = """<payment_item_detail>
274<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">""" % xmldict
275                item_id = 1
276                for item in ACCEPTANCEFEES[student.certcode].items():
277                    try:
278                        item_amt = 100 * int(item[1])
279                        bank = BANK_ACCOUNTS[item[0]]
280                        acct_num = bank[0]
281                        bank_id = bank[1]
282                        item_name = "%s (%s)" % (bank[2], item[0])
283                        xmltext += """
284<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)
285                        item_id += 1
286                    except:
287                        pass
288                xmldict['item_id'] = item_id
289                xmltext += """
290<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" />
291</item_details>
292</payment_item_detail>""" % xmldict
293            # no additional charges, determine faculty bank only
294            else:
295                bank = BANK_ACCOUNTS['acceptance']
296                xmldict['institution_acct'] = bank[0]
297                xmldict['institution_bank_id'] = bank[1]
298
299        # Other fees
300
301
302        if not xmltext and provider_amt == 0:
303            xmltext = """<payment_item_detail>
304<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
305<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" />
306</item_details>
307</payment_item_detail>""" % xmldict
308        elif not xmltext:
309            xmltext = """<payment_item_detail>
310<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
311<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" />
312<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" />
313</item_details>
314</payment_item_detail>""" % xmldict
315        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
316        xmlitems = ''
317        xmldoc = minidom.parseString(xmltext)
318        itemlist = xmldoc.getElementsByTagName('item_detail')
319        for s in itemlist:
320            xmlitems += "%s: %s, %s %s, %s (%s)  " % (
321                s.attributes['item_id'].value,
322                s.attributes['item_name'].value,
323                u'\u20a6',
324                int(s.attributes['item_amt'].value)/100,
325                s.attributes['acct_num'].value,
326                s.attributes['bank_id'].value,
327                )
328        self.context.p_split_data = xmlitems
329        self.context.provider_amt = provider_amt
330        self.amount_auth = int(100 * self.context.amount_auth)
331        hashargs = (
332            self.context.p_id +
333            PRODUCT_ID +
334            self.pay_item_id +
335            str(int(self.amount_auth)) +
336            self.site_redirect_url +
337            MAC)
338        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
339        return
340
341
342class CustomInterswitchPaymentRequestWebservicePageApplicant(
343    InterswitchPaymentRequestWebservicePageApplicant):
344    """Request webservice view for the CollegePAY gateway
345    """
346    grok.context(ICustomApplicantOnlinePayment)
347    gateway_host = HOST
348    gateway_url = URL
349    https = HTTPS
350
351class CustomInterswitchPaymentVerifyWebservicePageApplicant(
352    InterswitchPaymentVerifyWebservicePageApplicant):
353    """Payment verify view for the CollegePAY gateway
354    """
355    grok.context(ICustomApplicantOnlinePayment)
356    gateway_host = HOST
357    gateway_url = URL
358    https = HTTPS
359    mac = MAC
360    product_id = PRODUCT_ID
361
362class CustomInterswitchPaymentRequestWebservicePageStudent(
363    InterswitchPaymentRequestWebservicePageStudent):
364    """Request webservice view for the CollegePAY gateway
365    """
366    grok.context(ICustomStudentOnlinePayment)
367    gateway_host = HOST
368    gateway_url = URL
369    https = HTTPS
370    mac = MAC
371    product_id = PRODUCT_ID
372
373class CustomInterswitchPaymentVerifyWebservicePageStudent(
374    InterswitchPaymentVerifyWebservicePageStudent):
375    """Payment verify view for the CollegePAY gateway
376    """
377    grok.context(ICustomStudentOnlinePayment)
378    gateway_host = HOST
379    gateway_url = URL
380    https = HTTPS
381    mac = MAC
382    product_id = PRODUCT_ID
Note: See TracBrowser for help on using the repository browser.