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

Last change on this file since 13419 was 13414, checked in by Henrik Bettermann, 10 years ago

Determine net amount instead of gateway reduction. This is much easier to handle.

  • Property svn:keywords set to Id
File size: 19.5 KB
Line 
1## $Id: browser.py 13414 2015-11-09 07:08:21Z henrik $
2##
3## Copyright (C) 2012 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 httplib
19import hashlib
20import grok
21from zope.interface import Interface
22from zope.component import queryAdapter
23from waeup.kofa.interfaces import CLEARED
24from kofacustom.nigeria.interswitch.browser import (
25    InterswitchPaymentRequestWebservicePageStudent,
26    InterswitchPaymentRequestWebservicePageApplicant,
27    InterswitchPageStudent, InterswitchPageApplicant,
28    )
29from waeup.aaue.students.interfaces import ICustomStudentOnlinePayment
30from waeup.aaue.applicants.interfaces import ICustomApplicantOnlinePayment
31from waeup.aaue.interfaces import MessageFactory as _
32
33PRODUCT_ID_PT = '5040'
34PRODUCT_ID_REGULAR = '5845'
35SITE_NAME = 'aaue.waeup.org'
36PROVIDER_ACCT = '2022866811'
37PROVIDER_BANK_ID = '8'
38PROVIDER_ITEM_NAME = 'BT Education'
39INSTITUTION_NAME = 'AAU Ekpoma'
40CURRENCY = '566'
41GATEWAY_AMT = 250.0
42POST_ACTION = 'https://webpay.interswitchng.com/paydirect/pay'
43
44HOST = 'webpay.interswitchng.com'
45HTTPS = True
46
47URL = '/paydirect/services/TransactionQueryWs.asmx'
48httplib.HTTPSConnection.debuglevel = 0
49
50
51def gateway_net_amt(fee):
52    if fee > GATEWAY_AMT:
53        return fee - GATEWAY_AMT
54    return 0.0
55
56def contr_agreement(student):
57    if student.current_mode == 'found' or student.current_mode.endswith('_pt'):
58        return 'first'
59    return 'second'
60
61class CustomInterswitchPageApplicant(InterswitchPageApplicant):
62    """ View which sends a POST request to the Interswitch
63    CollegePAY payment gateway.
64
65    So far only PT application has been configured.
66    """
67    grok.context(ICustomApplicantOnlinePayment)
68    action = POST_ACTION
69    site_name = SITE_NAME
70    currency = CURRENCY
71    pay_item_id = '101'
72    product_id = PRODUCT_ID_PT
73    mac = '74424F1DFECD6058F153148255CDD55E16724B4F380ADB2C63C5D1D7A5675759010C8153DCB930AAF2D38903CBF7CE32B8A6BA2C16BBC46721DF2E3F3E4548E3'
74
75    def update(self):
76
77        error = self.init_update()
78        if error:
79            self.flash(error, type='danger')
80            self.redirect(self.url(self.context, '@@index'))
81            return
82        xmldict = {}
83        provider_amt = 1000.0
84        xmldict['institution_acct'] = '1010835352'
85        xmldict['institution_bank_id'] = '117'
86        xmldict['detail_ref'] = self.context.p_id
87        xmldict['provider_amt'] = 100 * provider_amt
88        xmldict['provider_acct'] = PROVIDER_ACCT
89        xmldict['provider_bank_id'] = PROVIDER_BANK_ID
90        xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
91        xmldict['institution_amt'] = 100 * (
92            self.context.amount_auth - provider_amt - GATEWAY_AMT)
93        xmldict['institution_item_name'] = self.context.p_category
94        xmldict['institution_name'] = INSTITUTION_NAME
95        # Interswitch amount is not part of the xml data
96        xmltext = """<payment_item_detail>
97<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s">
98<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" />
99<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" />
100</item_details>
101</payment_item_detail>""" % xmldict
102        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
103        self.context.provider_amt = provider_amt
104        self.context.gateway_amt = GATEWAY_AMT
105
106        hashargs = (
107            self.context.p_id +
108            PRODUCT_ID_PT +
109            self.pay_item_id +
110            str(int(self.amount_auth)) +
111            self.site_redirect_url +
112            self.mac)
113        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
114
115        return
116
117class CustomInterswitchPageStudent(InterswitchPageStudent):
118    """ View which sends a POST request to the Interswitch
119    CollegePAY payment gateway.
120    """
121    grok.context(ICustomStudentOnlinePayment)
122    action = POST_ACTION
123    site_name = SITE_NAME
124    currency = CURRENCY
125    pay_item_id = '101'
126    #mac = '74424F1DFECD6058F153148255CDD55E16724B4F380ADB2C63C5D1D7A5675759010C8153DCB930AAF2D38903CBF7CE32B8A6BA2C16BBC46721DF2E3F3E4548E3'
127    mac = '9718FA00B0F5070B388A9896ADCED9B2FB02D30F71E12E68BDADC63F6852A3496FF97D8A0F9DA9F753B911A49BB09BB87B55FD02046BD325C74C46C0123CF023'
128
129    def update(self):
130        error = self.init_update()
131
132        ######################################
133        #error = 'Sorry, Interswitch payments are temporarily disabled.'
134        ######################################
135
136        if error:
137            self.flash(error, type='danger')
138            self.redirect(self.url(self.context, '@@index'))
139            return
140
141        student = self.student
142        p_session = self.context.p_session
143        try:
144            academic_session = grok.getSite()['configuration'][str(p_session)]
145        except KeyError:
146            self.flash(_(u'Session configuration object is not available.'),
147                       type='danger')
148            self.redirect(self.url(self.context, '@@index'))
149            return
150        if contr_agreement(student) == 'first':
151            self.product_id = PRODUCT_ID_PT
152        else:
153            self.product_id = PRODUCT_ID_REGULAR
154
155        # To guarantee that cleared students pay both acceptance fee
156        # and school fees, the page can only be accessed
157        # for school fee payments if acceptance/clearance fee has
158        # been successfully queried/paid beforehand. This
159        # requirement applies to students in state 'cleared' and
160        # entry_session greater than 2013 only.
161        if self.context.p_category.startswith('schoolfee') and \
162            student.state == CLEARED and \
163            student.entry_session > 2012:
164            acceptance_fee_paid = False
165            for ticket in student['payments'].values():
166                if ticket.p_state == 'paid' and \
167                    ticket.p_category.startswith('clearance'):
168                    acceptance_fee_paid = True
169                    break
170            if not acceptance_fee_paid:
171                self.flash(
172                    _('Please pay acceptance fee first.'), type="danger")
173                self.redirect(self.url(self.context, '@@index'))
174                return
175
176        xmldict = self.xmldict
177        xmltext = ""
178        # Provider data
179        xmldict['detail_ref'] = self.context.p_id
180        xmldict['provider_acct'] = PROVIDER_ACCT
181        xmldict['provider_bank_id'] = PROVIDER_BANK_ID
182        xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
183        xmldict['institution_item_name'] = self.category
184        xmldict['institution_name'] = INSTITUTION_NAME
185        provider_amt = 0.0
186
187        # Schoolfee
188        if self.context.p_category.startswith('schoolfee'):
189            if contr_agreement(student) == 'first':
190                # First agreement
191                provider_amt = 1900.0
192                joint_venture_amt = 1100.0
193                aaue_share_amt = 1000.0
194                student_union_due_amt = gateway_net_amt(
195                    academic_session.union_fee)
196                student_welfare_assurance_amt = gateway_net_amt(
197                    academic_session.welfare_fee)
198                xmldict['institution_bank_id'] = '7'
199                xmldict['institution_acct'] = '1014847058'
200                if student.current_mode == 'found':
201                    self.pay_item_id = '103'
202                else:
203                    self.pay_item_id = '105'
204            else:
205                # Second agreement
206                provider_amt = 1500.0
207                joint_venture_amt = 1000.0
208                aaue_share_amt = 1500.0
209                student_union_due_amt = gateway_net_amt(
210                    academic_session.union_fee)
211                student_welfare_assurance_amt = gateway_net_amt(
212                    academic_session.welfare_fee)
213                xmldict['institution_bank_id'] = '117'
214                xmldict['institution_acct'] = '1010827641'
215                self.pay_item_id = '101'
216
217            xmldict['provider_amt'] = 100 * provider_amt
218            xmldict['joint_venture_amt'] = 100 * joint_venture_amt
219            xmldict['aaue_share_amt'] = 100 * aaue_share_amt
220            if self.context.p_category == 'schoolfee_incl':
221                # Schoolfee including additional fees
222                xmldict['student_union_due_amt'] = 100 * student_union_due_amt
223                xmldict['student_welfare_assurance_amt'] = 100 * student_welfare_assurance_amt
224                xmldict['institution_amt'] = 100 * (
225                    gateway_net_amt(self.context.amount_auth)
226                    - provider_amt
227                    - joint_venture_amt
228                    - aaue_share_amt
229                    - student_union_due_amt
230                    - student_welfare_assurance_amt)
231                xmltext = """<payment_item_detail>
232<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
233<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" />
234<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" />
235<item_detail item_id="3" item_name="Joint Venture" item_amt="%(joint_venture_amt)d" bank_id="51" acct_num="5060023759" />
236<item_detail item_id="4" item_name="AAUE Share" item_amt="%(aaue_share_amt)d" bank_id="51" acct_num="5060020947" />
237<item_detail item_id="5" item_name="Student Union" item_amt="%(student_union_due_amt)d" bank_id="123" acct_num="1006360118" />
238<item_detail item_id="6" item_name="Student Welfare Assurance" item_amt="%(student_welfare_assurance_amt)d" bank_id="31" acct_num="1006407792" />
239</item_details>
240</payment_item_detail>""" % xmldict
241            else:
242                # Schoolfee without additional fees
243                xmldict['institution_amt'] = 100 * (
244                    gateway_net_amt(self.context.amount_auth)
245                    - provider_amt
246                    - joint_venture_amt
247                    - aaue_share_amt)
248                xmltext = """<payment_item_detail>
249<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
250<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" />
251<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" />
252<item_detail item_id="3" item_name="Joint Venture" item_amt="%(joint_venture_amt)d" bank_id="51" acct_num="5060023759" />
253<item_detail item_id="4" item_name="AAUE Share" item_amt="%(aaue_share_amt)d" bank_id="51" acct_num="5060020947" />
254</item_details>
255</payment_item_detail>""" % xmldict
256
257
258        # Clearance
259        elif self.context.p_category.startswith('clearance'):
260            if contr_agreement(student) == 'first':
261                # First agreement
262                if student.current_mode == 'found':
263                    self.pay_item_id = '102'
264                else:
265                    self.pay_item_id = '104'
266                xmldict['institution_acct'] = '1014066976'
267                xmldict['institution_bank_id'] = '117'
268            else:
269                # Second agreement
270                self.pay_item_id = '102'
271                xmldict['institution_acct'] = '1010827641'
272                xmldict['institution_bank_id'] = '117'
273
274            if self.context.p_category.endswith('_incl'):
275                # Clearance including additional fees
276                gown_fee_amt = gateway_net_amt(academic_session.matric_gown_fee)
277                aaue_lf_fee_amt = gateway_net_amt(academic_session.lapel_fee)
278                xmldict['gown_fee_amt'] = 100 * gown_fee_amt
279                xmldict['aaue_lf_fee_amt'] = 100 * aaue_lf_fee_amt
280                xmldict['institution_amt'] = 100 * (
281                    gateway_net_amt(self.context.amount_auth)
282                    - gown_fee_amt
283                    - aaue_lf_fee_amt)
284                xmltext = """<payment_item_detail>
285<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
286<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" />
287<item_detail item_id="2" item_name="Matriculation Gown Fee" item_amt="%(gown_fee_amt)d" bank_id="51" acct_num="5060020947" />
288<item_detail item_id="3" item_name="AAU File-Lapel Fee" item_amt="%(aaue_lf_fee_amt)d" bank_id="51" acct_num="4010660109" />
289</item_details>
290</payment_item_detail>""" % xmldict
291
292            else:
293                # Clearance without additional fees
294                xmldict['institution_amt'] = 100 * (
295                    gateway_net_amt(self.context.amount_auth))
296                xmltext = """<payment_item_detail>
297<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
298<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" />
299</item_details>
300</payment_item_detail>""" % xmldict
301
302        # Union Dues
303        elif self.context.p_category == 'union':
304            self.pay_item_id = '103'
305            xmldict['institution_acct'] = '1006360118'
306            xmldict['institution_bank_id'] = '123'
307            xmldict['institution_amt'] = 100 * (
308                gateway_net_amt(self.context.amount_auth))
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_details>
313</payment_item_detail>""" % xmldict
314
315        # Lapel/File
316        elif self.context.p_category == 'lapel':
317            self.pay_item_id = '104'
318            xmldict['institution_acct'] = '4010660109'
319            xmldict['institution_bank_id'] = '51'
320            xmldict['institution_amt'] = 100 * (
321                gateway_net_amt(self.context.amount_auth))
322            xmltext = """<payment_item_detail>
323<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
324<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" />
325</item_details>
326</payment_item_detail>""" % xmldict
327
328        # Welfare Assurance
329        elif self.context.p_category == 'welfare':
330            self.pay_item_id = '105'
331            xmldict['institution_acct'] = '1006407792'
332            xmldict['institution_bank_id'] = '123'
333            xmldict['institution_amt'] = 100 * (
334                gateway_net_amt(self.context.amount_auth))
335            xmltext = """<payment_item_detail>
336<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
337<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" />
338</item_details>
339</payment_item_detail>""" % xmldict
340
341        # Matric Gown
342        elif self.context.p_category == 'matric_gown':
343            self.pay_item_id = '106'
344            xmldict['institution_acct'] = '5060023429'
345            xmldict['institution_bank_id'] = '51'
346            xmldict['institution_amt'] = 100 * (
347                gateway_net_amt(self.context.amount_auth))
348            xmltext = """<payment_item_detail>
349<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
350<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" />
351</item_details>
352</payment_item_detail>""" % xmldict
353
354        # Concessional
355        elif self.context.p_category == 'concessional':
356            self.pay_item_id = '107'
357            xmldict['institution_acct'] = '1010835352'
358            xmldict['institution_bank_id'] = '117'
359            xmldict['institution_amt'] = 100 * (
360                gateway_net_amt(self.context.amount_auth))
361            xmltext = """<payment_item_detail>
362<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
363<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" />
364</item_details>
365</payment_item_detail>""" % xmldict
366
367        # Hostel Maintenance
368        elif self.context.p_category == 'hostel_maintenance':
369            self.pay_item_id = '109'
370            xmldict['institution_acct'] = '1006406795'
371            xmldict['institution_bank_id'] = '123'
372            xmldict['institution_amt'] = 100 * (
373                gateway_net_amt(self.context.amount_auth))
374            xmltext = """<payment_item_detail>
375<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
376<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" />
377</item_details>
378</payment_item_detail>""" % xmldict
379
380        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
381        self.context.provider_amt = provider_amt
382        self.context.gateway_amt = GATEWAY_AMT
383        hashargs = (
384            self.context.p_id +
385            self.product_id +
386            self.pay_item_id +
387            str(int(self.amount_auth)) +
388            self.site_redirect_url +
389            self.mac)
390        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
391        return
392
393
394class CustomInterswitchPaymentRequestWebservicePageApplicant(
395    InterswitchPaymentRequestWebservicePageApplicant):
396    """ Request webservice view for the CollegePAY gateway
397
398    So far only PT application has been configured.
399    """
400    grok.context(ICustomApplicantOnlinePayment)
401    product_id = PRODUCT_ID_PT
402    gateway_host = HOST
403    gateway_url = URL
404    https = HTTPS
405
406class CustomInterswitchPaymentRequestWebservicePageStudent(
407    InterswitchPaymentRequestWebservicePageStudent):
408    """ Request webservice view for the CollegePAY gateway
409    """
410    grok.context(ICustomStudentOnlinePayment)
411    gateway_host = HOST
412    gateway_url = '/paydirect/api/v1/gettransaction.json'
413    https = HTTPS
414    mac = '9718FA00B0F5070B388A9896ADCED9B2FB02D30F71E12E68BDADC63F6852A3496FF97D8A0F9DA9F753B911A49BB09BB87B55FD02046BD325C74C46C0123CF023'
415
416    @property
417    def product_id(self):
418        if contr_agreement(self.context.student) == 'first':
419            return PRODUCT_ID_PT
420        return PRODUCT_ID_REGULAR
Note: See TracBrowser for help on using the repository browser.