source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/helpers.py

Last change on this file was 17907, checked in by Henrik Bettermann, 2 months ago

Remita's programmers may not know that case sensitivity matters
in programming languages.

  • Property svn:keywords set to Id
File size: 6.6 KB
RevLine 
[14735]1## $Id: helpers.py 17907 2024-08-29 06:29:26Z henrik $
2##
3## Copyright (C) 2017 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##
18"""General helper functions for the remita module in custom packages.
19"""
[14737]20import grok
[14735]21from datetime import datetime
22import httplib
23import hashlib
24import json
25
26from zope.event import notify
27from kofacustom.nigeria.interfaces import MessageFactory as _
28
29def get_JSON_POST_response(
30        merchantId, serviceTypeId, api_key, orderId,
31        amount, responseurl, host, url, https, fullname, email, lineitems):
[14753]32    hashargs =  merchantId + serviceTypeId + orderId + str(amount) + responseurl + api_key
[14735]33    hashvalue = hashlib.sha512(hashargs).hexdigest()
34    headers={
35        'Content-Type':'application/json; charset=utf-8',
36    }
37    if https:
38        h = httplib.HTTPSConnection(host)
39    else:
40        h = httplib.HTTPConnection(host)
41    data = {
42            "merchantId":merchantId,
43            "serviceTypeId":serviceTypeId,
44            "totalAmount":amount,
45            "hash":hashvalue,
46            "payerName":fullname,
47            "payerEmail":email,
48            "orderId":orderId,
49            "responseurl":responseurl,
50            "lineItems":lineitems
51            }
[14769]52    try:
53        h.request("POST", url, body=json.dumps(data), headers=headers)
[14916]54        resp = h.getresponse()
[14769]55    except:
56        return {'error': 'Socket Error: Connection to Remita gateway refused.'}
[14737]57    if resp.status!=200:
[14916]58        return {'error': 'Connection Error (%s, %s)' % (resp.status, resp.reason)}
[14735]59    jsonout = resp.read()
[14736]60    try:
61        parsed_json = json.loads(jsonout[6:-1])
62    except ValueError:
[14737]63        return {'error': 'No JSON response'}
[14735]64    return parsed_json
65
66def get_payment_status_via_rrr(merchantId, api_key, RRR, host, https):
[14738]67    RRR = RRR.rstrip()
[14735]68    hashargs =  RRR + api_key + merchantId
69    hashvalue = hashlib.sha512(hashargs).hexdigest()
70    headers={
71        'Content-Type':'application/json; charset=utf-8',
72    }
[17146]73   
74    # url = '/remita/ecomm/%s/%s/%s/status.reg' % (merchantId, RRR, hashvalue)
75
76    # On 28/10/22 Balogun Olalekan wrote:
77    # Kindly update the transaction validation endpoint being used to the below.
78    # https://login.remita.net/remita/exapp/api/v1/send/api/echannelsvc/{{merchantId}}/{{rrr}}/{{apiHash}}/status.reg.
79
80    url = '/remita/exapp/api/v1/send/api/echannelsvc/%s/%s/%s/status.reg' % (merchantId, RRR, hashvalue)
81
[14735]82    if https:
83        h = httplib.HTTPSConnection(host)
84    else:
85        h = httplib.HTTPConnection(host)
[14769]86    try:
87        h.request("GET", url, headers=headers)
[15916]88        resp = h.getresponse()
[14769]89    except:
90        return {'error': 'Socket Error: Connection to Remita gateway refused.'}
[14737]91    if resp.status!=200:
[14738]92        return {'error': 'Connection error (%s, %s)' % (resp.status, resp.reason)}
[14735]93    jsonout = resp.read()
[14736]94    try:
95        parsed_json = json.loads(jsonout)
96    except ValueError:
[14737]97        return {'error': 'No JSON response'}
[14735]98    return parsed_json
99
[14737]100def query_remita(payment, merchantId, api_key, RRR, host, https, verify):
101
102    jr = get_payment_status_via_rrr(merchantId, api_key, RRR, host, https)
103    error = jr.get('error')
104    if error:
105        msg = log = error
106        return False, msg, log
107
108    # A typical JSON response
109    # {
110    # u'orderId': u'3456346346',
111    # u'status': u'021',
112    # u'amount': 1000.0,
113    # u'transactiontime': u'2017-07-31 11:17:24 AM',
114    # u'message': u'Transaction Pending',
115    # u'lineitems': [{u'status': u'021', u'lineItemsId': u'itemid1'},
116    #                {u'status': u'021', u'lineItemsId': u'itemid2'}
117    #               ],
118    # u'RRR': u'280007640804'}
119
120    payment.r_code = jr['status']
121    payment.r_desc = jr['message']
122    payment.r_amount_approved = jr['amount']
[15916]123    try:
124        payment.r_pay_reference = jr['RRR']
125    except KeyError:
[17907]126        # Remita's programmers may not know that case sensitivity matters
127        # in programming languages.
128        try:
129            payment.r_pay_reference = jr['rrr']
130        except KeyError:
131            msg = _('Error message from Remita: ${a}', mapping = {'a': payment.r_desc})
132            log = 'unsuccessful response for %s payment %s: %s' % (
133                payment.p_category, payment.p_id, str(jr))
134            payment.p_state = 'failed'
135            notify(grok.ObjectModifiedEvent(payment))
136            return False, msg, log
[15730]137    #payment.r_company = u'remita'
[14743]138    if payment.r_code not in ('00', '01'):
[14788]139        msg = _('Unsuccessful response: ${a}', mapping = {'a': payment.r_desc})
140        log = 'unsuccessful response for %s payment %s: %s' % (
[14737]141            payment.p_category, payment.p_id, payment.r_desc)
142        payment.p_state = 'failed'
143        notify(grok.ObjectModifiedEvent(payment))
144        return False, msg, log
[14820]145    if round(payment.r_amount_approved/10.0, 0) != round(
146        payment.amount_auth/10.0, 0):
[14788]147        msg = _('Response amount does not match.')
148        log = 'wrong response for %s payment %s: %s' % (
[14737]149            payment.p_category, payment.p_id, str(jr))
150        payment.p_state = 'failed'
151        notify(grok.ObjectModifiedEvent(payment))
152        return False, msg, log
[14806]153    orderId = jr.get('orderId', None)
154    if orderId and orderId != payment.p_id:
[14788]155        msg = _('Response order id does not match.')
156        log = 'wrong response for %s payment %s: %s' % (
[14737]157            payment.p_category, payment.p_id, str(jr))
158        payment.p_state = 'failed'
159        notify(grok.ObjectModifiedEvent(payment))
160        return False, msg, log
161    payment.p_state = 'paid'
162    if not verify:
163        payment.payment_date = datetime.utcnow()
[14788]164    msg = _('Successful response received')
165    log = 'valid response for %s payment %s: %s' % (
[14737]166        payment.p_category, payment.p_id, str(jr))
167    notify(grok.ObjectModifiedEvent(payment))
168    return True, msg, log
169
[14735]170def write_payments_log(id, payment):
171    payment.logger.info(
172        '%s,%s,%s,%s,%s,%s,%s,%s,,,' % (
173        id, payment.p_id, payment.p_category,
174        payment.amount_auth, payment.r_code,
175        payment.provider_amt, payment.gateway_amt,
176        payment.thirdparty_amt))
Note: See TracBrowser for help on using the repository browser.