Changeset 15589
- Timestamp:
- 17 Sep 2019, 18:31:10 (5 years ago)
- Location:
- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact
- Files:
-
- 1 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/applicantsbrowser.py
r15586 r15589 26 26 from waeup.kofa.browser.viewlets import ManageActionButton 27 27 from waeup.kofa.applicants.browser import OnlinePaymentDisplayFormPage as OPDPApplicant 28 from kofacustom.nigeria.etranzact.helpers import (write_payments_log) 28 from kofacustom.nigeria.etranzact.helpers import ( 29 write_payments_log, process_response, query_history) 30 from kofacustom.nigeria.applicants.browser import NigeriaOnlinePaymentDisplayFormPage 29 31 from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment 30 32 from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment … … 42 44 except KeyError: 43 45 return False 44 45 # Buttons46 46 47 47 class EtranzactActionButtonApplicant(ManageActionButton): … … 61 61 return '' 62 62 return self.view.url(self.view.context, self.target) 63 64 # Forwarding pages65 63 66 64 class EtranzactPageApplicant(KofaPage): … … 96 94 if time_delta.days > 7: 97 95 return _("This payment ticket is too old. Please create a new ticket.") 98 self.responseurl = self.url(self.context, ' query_etranzact')96 self.responseurl = self.url(self.context, 'receive_etranzact') 99 97 # Already now it becomes a eTranzact payment 100 98 self.context.r_company = u'etranzact' … … 116 114 return 117 115 return 116 117 class EtranzactReceiveResponseApplicant(NigeriaOnlinePaymentDisplayFormPage): 118 """ View that receives the response from eTrantact payment gateway. 119 """ 120 #grok.context(INigeriaApplicantOnlinePayment) 121 grok.name('receive_etranzact') 122 #grok.require('waeup.payApplicant') 123 #label = _('Response from eTranzact') 124 125 secret_key = SECRET_KEY 126 terminal_id = TERMINAL_ID 127 128 def update(self): 129 super(EtranzactReceiveResponseApplicant, self).update() 130 if not module_activated(self.context.__parent__.__parent__.year): 131 return 132 applicant = self.context.__parent__ 133 form = self.request.form 134 verify = False 135 if self.context.p_state == 'paid': 136 verify = True 137 success, msg, log = process_response(self.context, form, self, verify) 138 applicant.writeLogMessage(self, log) 139 if not success: 140 self.flash(msg, type='danger') 141 return 142 write_payments_log(applicant.applicant_id, self.context) 143 flashtype, msg, log = self.context.doAfterApplicantPayment() 144 if log is not None: 145 applicant.writeLogMessage(self, log) 146 self.flash(msg, type=flashtype) 147 return 148 149 class EtranzactRequeryHistoryApplicant(KofaPage): 150 """ Request POST redirect from eTranzact 151 """ 152 153 grok.context(INigeriaApplicantOnlinePayment) 154 grok.name('requery_history') 155 grok.require('waeup.payApplicant') 156 grok.template('requery_etranzact') 157 label = _('Requery eTranzact history') 158 submit_button = _('Requery now') 159 160 host = HOST 161 https = HTTPS 162 secret_key = SECRET_KEY 163 terminal_id = TERMINAL_ID 164 logo_url = LOGO_URL 165 166 @property 167 def action(self): 168 if self.https: 169 return 'https://' + self.host + '/webconnect/v3/query.jsp' 170 return 'http://' + self.host + '/webconnect/v3/query.jsp' 171 172 def update(self): 173 if not module_activated(self.context.__parent__.__parent__.year): 174 return 175 self.responseurl = self.url(self.context, 'receive_etranzact') 176 self.transaction_id = self.context.p_id 177 return -
main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/helpers.py
r15586 r15589 37 37 payment.thirdparty_amt)) 38 38 39 def get_caller_response(host, https, terminal_id, transaction_id, responseurl, 40 amount_auth, email, phone, display_fullname, hashvalue, 41 logo_url): 42 headers={"Content-type": "application/x-www-form-urlencoded", 43 "Accept": "text/plain"} 44 url = "/webconnect/v3/caller.jsp" 45 if https: 46 h = httplib.HTTPSConnection(host) 47 else: 48 h = httplib.HTTPConnection(host) 49 args = {'TERMINAL_ID': terminal_id, 50 'TRANSACTION_ID': transaction_id, 51 'RESPONSE_URL': responseurl, 52 'AMOUNT': amount_auth, 53 'EMAIL': email, 54 'PHONENO': phone, 55 'FULL_NAME': display_fullname, 56 'CURRENCY_CODE': 'NGN', 57 'CHECKSUM': hashvalue, 58 'LOGO_URL': logo_url, 59 } 60 h.request('POST', url, urlencode(args), headers) 61 return 62 response = h.getresponse() 63 if response.status!=200: 64 return 'Connection error (%s, %s)' % (response.status, response.reason) 65 resp = response.read() 66 return resp 67 #resp = resp.replace('\r\n','') 68 ## eTranzact sends strange HTML tags which must be removed. 69 #resp = re.sub("<.*?>", "", resp) 70 #return resp 71 72 def get_query_response(host, terminal_id, transaction_id, https): 39 def query_history(host, terminal_id, transaction_id, https, responseurl): 73 40 headers={"Content-type": "application/x-www-form-urlencoded", 74 41 "Accept": "text/plain"} … … 80 47 args = {'TERMINAL_ID': terminal_id, 81 48 'TRANSACTION_ID': transaction_id, 82 'RESPONSE_URL': 'https://www.waeup.org'} 49 } 50 #args['RESPONSE_URL'] = responseurl 83 51 h.request('POST', url, urlencode(args), headers) 84 52 response = h.getresponse() … … 90 58 resp = re.sub("<.*?>", "", resp) 91 59 return resp 60 61 # A sample caller response sent to the RESPONSE_URL 62 63 # http://salsa:8080/app/applicants/cbt2015/449072/p5679522929425/receive_etranzact? 64 # AMOUNT=3333.0& 65 # DESCRIPTION=& 66 # CHECKSUM=8aab3904652f8ba69ebed42d3bae80a2& 67 # EMAIL=aa%40aa.de& 68 # SUCCESS=C& 69 # MESSAGE=Cancel& 70 # LOGO_URL=https%3A%2F%2Fiuokada.waeup.org%2Fstatic_custom%2Fiou_logo.png& 71 # RESPONSE_URL=http%3A%2F%2Fsalsa%3A8080%2Fapp%2Fapplicants%2Fcbt2015%2F449072%2Fp5679522929425%2Freceive_etranzact& 72 # CURRENCY_CODE=NGN& 73 # TERMINAL_ID=0000000001& 74 # TRANSACTION_ID=p5679522929425& 75 # MERCHANT_CODE=0339990001& 76 # RESPONSE_CODE=C& 77 # FINAL_CHECKSUM=E524590DBFAB719EEE428C778FFF1650& 78 # STATUS_REASON=Cancel& 79 # TRANS_NUM=01ESA20190913062149AHGUHQ& 80 # CARD_NO=null& 81 # CARD_TYPE=null 82 83 # A sample query response sent to the RESPONSE_URL 84 85 # http://salsa:8080/app/applicants/cbt2015/449072/p5686487280654/receive_etranzact? 86 # LOGO_URL=https%3A%2F%2Fiuokada.waeup.org%2Fstatic_custom%2Fiou_logo.png& 87 # RESPONSE_URL=http%3A%2F%2Fsalsa%3A8080%2Fapp%2Fapplicants%2Fcbt2015%2F449072%2Fp5686487280654%2Freceive_etranzact& 88 # CURRENCY_CODE=NGN& 89 # TERMINAL_ID=0000000001& 90 # TRANSACTION_ID=p5686487280654& 91 # AMOUNT=3333.0& 92 # DESCRIPTION=& 93 # CHECKSUM=3886118fcd91a376cc95c48c94dc499a& 94 # MERCHANT_CODE=0339990001& 95 # EMAIL=aa%40aa.de& 96 # SUCCESS=0& 97 # FINAL_CHECKSUM=EE105B703F84B1D67D0A4234622C03E8& 98 # STATUS_REASON=Approved& 99 # TRANS_NUM=01ESA20190916164636L2UTU7& 100 # CARD_NO=506066XXXXXXXXX6666& 101 # CARD_TYPE=Verve 102 103 def process_response(payment, form, view, verify): 104 success = form.get('RESPONSE_CODE', None) 105 if not success: 106 msg = _('No valid response from eTranzact.') 107 log = 'No valid response from eTranzact for payment %s' % payment.p_id 108 payment.p_state = 'failed' 109 notify(grok.ObjectModifiedEvent(payment)) 110 return False, msg, log 111 # Compute final checksum 112 transaction_id = payment.p_id 113 amount = "%.1f" % payment.amount_auth 114 responseurl = view.url(payment, 'receive_etranzact') 115 hashargs = success + amount + view.terminal_id + transaction_id \ 116 + responseurl + view.secret_key 117 final_checksum = hashlib.md5(hashargs).hexdigest().upper() 118 if form.get('FINAL_CHECKSUM', None) != final_checksum: 119 msg = _('Wrong checksum.') 120 log = 'wrong checksum for %s payment %s: %s' % ( 121 payment.p_category, payment.p_id, str(form)) 122 return False, msg, log 123 payment.r_code = form.get('RESPONSE_CODE', None) 124 payment.r_desc = form.get('STATUS_REASON', None) # MESSAGE also available 125 payment.r_amount_approved = float(form.get('AMOUNT', None)) 126 payment.r_pay_reference = form.get('TRANS_NUM', None) 127 payment.r_card_num = "%s %s" % (form.get('CARD_TYPE', None), 128 form.get('CARD_NO', None)) 129 payment.r_company = u'etranzact' 130 if payment.r_code != '0': 131 msg = _('Unsuccessful response: ${a}', mapping = {'a': payment.r_desc}) 132 log = 'unsuccessful response for %s payment %s: %s' % ( 133 payment.p_category, payment.p_id, payment.r_desc) 134 payment.p_state = 'failed' 135 notify(grok.ObjectModifiedEvent(payment)) 136 return False, msg, log 137 if round(payment.r_amount_approved/10.0, 0) != round( 138 payment.amount_auth/10.0, 0): 139 msg = _('Response amount does not match.') 140 log = 'wrong response for %s payment %s: %s' % ( 141 payment.p_category, payment.p_id, str(form)) 142 payment.p_state = 'failed' 143 notify(grok.ObjectModifiedEvent(payment)) 144 return False, msg, log 145 transaction_id = form.get('TRANSACTION_ID', None) 146 if transaction_id != payment.p_id: 147 msg = _('Response transaction id does not match.') 148 log = 'wrong response for %s payment %s: %s' % ( 149 payment.p_category, payment.p_id, str(form)) 150 payment.p_state = 'failed' 151 notify(grok.ObjectModifiedEvent(payment)) 152 return False, msg, log 153 payment.p_state = 'paid' 154 if not verify: 155 payment.payment_date = datetime.utcnow() 156 msg = _('Successful response received') 157 log = 'valid response for %s payment %s: %s' % ( 158 payment.p_category, payment.p_id, str(form)) 159 notify(grok.ObjectModifiedEvent(payment)) 160 return True, msg, log -
main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/tests.py
r15586 r15589 21 21 import json 22 22 import hashlib 23 import httplib 24 from urllib import urlencode 23 25 from datetime import datetime, timedelta, date 24 26 from zope.component import createObject, getUtility … … 31 33 from kofacustom.nigeria.testing import FunctionalLayer 32 34 from kofacustom.nigeria.etranzact.helpers import ( 33 get_query_response, get_caller_response)35 query_history,) 34 36 35 37 #from kofacustom.nigeria.etranzact.helpers import (query_etranzact) … … 57 59 return func 58 60 61 def post_caller(host, https, terminal_id, transaction_id, responseurl, 62 amount_auth, email, phone, display_fullname, hashvalue, 63 logo_url): 64 headers={"Content-type": "application/x-www-form-urlencoded", 65 "Accept": "text/plain"} 66 url = "/webconnect/v3/caller.jsp" 67 if https: 68 h = httplib.HTTPSConnection(host) 69 else: 70 h = httplib.HTTPConnection(host) 71 args = {'TERMINAL_ID': terminal_id, 72 'TRANSACTION_ID': transaction_id, 73 'RESPONSE_URL': responseurl, 74 'AMOUNT': amount_auth, 75 'EMAIL': email, 76 'PHONENO': phone, 77 'FULL_NAME': display_fullname, 78 'CURRENCY_CODE': 'NGN', 79 'CHECKSUM': hashvalue, 80 'LOGO_URL': logo_url, 81 } 82 h.request('POST', url, urlencode(args), headers) 83 return 84 response = h.getresponse() 85 if response.status!=200: 86 return 'Connection error (%s, %s)' % (response.status, response.reason) 87 resp = response.read() 88 return resp 89 90 def create_transaction(transaction_id): 91 responseurl = 'http://xxxx' 92 amount = '4444.0' 93 email = 'aa@aa.ng' 94 phone = '12324' 95 display_fullname = 'Tester' 96 logo_url = 'http://xxxx' 97 hashargs = amount + TERMINAL_ID + transaction_id \ 98 + responseurl + 'DEMO_KEY' 99 hashvalue = hashlib.md5(hashargs).hexdigest() 100 response = post_caller(HOST, HTTPS, TERMINAL_ID, 101 transaction_id, responseurl, 102 amount, email, phone, 103 display_fullname, hashvalue, 104 logo_url) 105 return response 106 107 59 108 class HelperTests(unittest.TestCase): 60 109 61 110 terminal_id = TERMINAL_ID 62 111 63 def _create_transaction(self, transaction_id):64 responseurl = 'http://xxxx'65 amount = '4444.0'66 email = 'aa@aa.ng'67 phone = '12324'68 display_fullname = 'Tester'69 logo_url = 'http://xxxx'70 hashargs = amount + self.terminal_id + transaction_id \71 + responseurl + 'DEMO_KEY'72 hashvalue = hashlib.md5(hashargs).hexdigest()73 response = get_caller_response(HOST, HTTPS, self.terminal_id,74 transaction_id, responseurl,75 amount, email, phone,76 display_fullname, hashvalue,77 logo_url)78 return response79 80 112 @external_test 81 def test_query_ etranzact(self):113 def test_query_history(self): 82 114 transaction_id = str(random.randint(100000000, 999999999)) 83 response = get_query_response(HOST, self.terminal_id,84 transaction_id, HTTPS )115 response = query_history(HOST, self.terminal_id, 116 transaction_id, HTTPS, 'http://xxxxx') 85 117 self.assertEqual( 86 118 response, … … 88 120 % transaction_id) 89 121 # Okay, let's create a transaction 90 caller_response = self._create_transaction(transaction_id)122 caller_response = create_transaction(transaction_id) 91 123 self.assertEqual(caller_response, None) 92 124 # It seems that the transaction has been created but we don't get a 93 125 # useful response 94 query_response = get_query_response(HOST, self.terminal_id,95 transaction_id, HTTPS )126 query_response = query_history(HOST, self.terminal_id, 127 transaction_id, HTTPS, 'http://xxxxx') 96 128 self.assertEqual(query_response, '') 97 129 # The same, an 'empty' response obviously means that the transaction 98 # was found. The result was probably sent to the response_url. 130 # was found. The result was sent to the response_url (see below). 131 # We need browser tests. 99 132 return 100 133 … … 126 159 127 160 @external_test 128 def test_ applicant_etranzact_form(self):129 # Manager can access Etranzact form161 def test_views(self): 162 # Manager can access eTranzact form 130 163 self.browser.getLink("Pay via eTranzact").click() 131 164 self.assertTrue("Pay now" in self.browser.contents) 132 # Means of testing end here. 165 # Means of testing end here. We have to manually 166 # create an eTranzact transaction. 167 logo_url = 'http://xxxx' 168 responseurl = self.payment_url + '/receive_etranzact' 169 amount = "%.1f" % self.payment.amount_auth 170 customer = self.applicant 171 hashargs = amount + TERMINAL_ID + self.payment.p_id \ 172 + responseurl + 'DEMO_KEY' 173 hashvalue = hashlib.md5(hashargs).hexdigest() 174 post_caller(HOST, HTTPS, TERMINAL_ID, 175 self.payment.p_id, responseurl, 176 self.payment.amount_auth, customer.email, 177 customer.phone, 178 customer.display_fullname, hashvalue, 179 logo_url) 133 180 return 134 181
Note: See TracChangeset for help on using the changeset viewer.