fix(mpesa-settings): add test cases to verify transactions
This commit is contained in:
parent
5c29eb08c4
commit
c8a04fec35
@ -26,11 +26,19 @@ class MpesaSettings(Document):
|
||||
def on_update(self):
|
||||
create_custom_pos_fields()
|
||||
create_payment_gateway('Mpesa-' + self.payment_gateway_name, settings='Mpesa Settings', controller=self.payment_gateway_name)
|
||||
create_mode_of_payment('Mpesa-' + self.payment_gateway_name, payment_type="Phone")
|
||||
call_hook_method('payment_gateway_enabled', gateway='Mpesa-' + self.payment_gateway_name, payment_channel="Phone")
|
||||
|
||||
# required to fetch the bank account details from the payment gateway account
|
||||
frappe.db.commit()
|
||||
create_mode_of_payment('Mpesa-' + self.payment_gateway_name, payment_type="Phone")
|
||||
|
||||
def request_for_payment(self, **kwargs):
|
||||
response = frappe._dict(generate_stk_push(**kwargs))
|
||||
if frappe.flags.in_test:
|
||||
from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import get_payment_request_response_payload
|
||||
response = frappe._dict(get_payment_request_response_payload())
|
||||
else:
|
||||
response = frappe._dict(generate_stk_push(**kwargs))
|
||||
|
||||
self.handle_api_response("CheckoutRequestID", kwargs, response)
|
||||
|
||||
def get_account_balance_info(self):
|
||||
@ -39,7 +47,13 @@ class MpesaSettings(Document):
|
||||
reference_docname=self.name,
|
||||
doc_details=vars(self)
|
||||
)
|
||||
response = frappe._dict(get_account_balance(payload))
|
||||
|
||||
if frappe.flags.in_test:
|
||||
from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import get_test_account_balance_response
|
||||
response = frappe._dict(get_test_account_balance_response())
|
||||
else:
|
||||
response = frappe._dict(get_account_balance(payload))
|
||||
|
||||
self.handle_api_response("ConversationID", payload, response)
|
||||
|
||||
def handle_api_response(self, global_id, request_dict, response):
|
||||
@ -92,7 +106,6 @@ def sanitize_mobile_number(number):
|
||||
def verify_transaction(**kwargs):
|
||||
"""Verify the transaction result received via callback from stk."""
|
||||
transaction_response = frappe._dict(kwargs["Body"]["stkCallback"])
|
||||
frappe.logger().debug(transaction_response)
|
||||
|
||||
checkout_id = getattr(transaction_response, "CheckoutRequestID", "")
|
||||
request = frappe.get_doc("Integration Request", checkout_id)
|
||||
@ -148,14 +161,13 @@ def process_balance_info(**kwargs):
|
||||
return
|
||||
|
||||
transaction_data = frappe._dict(loads(request.data))
|
||||
frappe.logger().debug(account_balance_response)
|
||||
|
||||
if account_balance_response["ResultCode"] == 0:
|
||||
try:
|
||||
result_params = account_balance_response["ResultParameters"]["ResultParameter"]
|
||||
|
||||
balance_info = fetch_param_value(result_params, "AccountBalance", "Key")
|
||||
balance_info = convert_to_json(balance_info)
|
||||
balance_info = format_string_to_json(balance_info)
|
||||
|
||||
ref_doc = frappe.get_doc(transaction_data.reference_doctype, transaction_data.reference_docname)
|
||||
ref_doc.db_set("account_balance", balance_info)
|
||||
@ -168,15 +180,15 @@ def process_balance_info(**kwargs):
|
||||
else:
|
||||
request.handle_failure(account_balance_response)
|
||||
|
||||
def convert_to_json(balance_info):
|
||||
def format_string_to_json(balance_info):
|
||||
"""
|
||||
Convert string to json.
|
||||
Format string to json.
|
||||
|
||||
e.g: '''Working Account|KES|481000.00|481000.00|0.00|0.00'''
|
||||
=> {'Working Account': {'current_balance': '481000.00',
|
||||
'available_balance': '481000.00',
|
||||
'reserved_balance': '0.00',
|
||||
'uncleared_balance': '0.00'}
|
||||
'uncleared_balance': '0.00'}}
|
||||
"""
|
||||
balance_dict = frappe._dict()
|
||||
for account_info in balance_info.split("&"):
|
||||
|
@ -2,9 +2,239 @@
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
from json import dumps
|
||||
import frappe
|
||||
import unittest
|
||||
from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_settings import process_balance_info, verify_transaction
|
||||
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
|
||||
|
||||
class TestMpesaSettings(unittest.TestCase):
|
||||
pass
|
||||
def test_creation_of_payment_gateway(self):
|
||||
mpesa_doc = create_mpesa_settings(payment_gateway_name="_Test")
|
||||
|
||||
mode_of_payment = frappe.get_doc("Mode of Payment", "Mpesa-_Test")
|
||||
self.assertTrue(frappe.db.exists("Payment Gateway Account", {'payment_gateway': "Mpesa-_Test"}))
|
||||
self.assertTrue(mode_of_payment.name)
|
||||
self.assertEquals(mode_of_payment.type, "Phone")
|
||||
|
||||
def test_processing_of_account_balance(self):
|
||||
mpesa_doc = create_mpesa_settings(payment_gateway_name="_Account Balance")
|
||||
mpesa_doc.get_account_balance_info()
|
||||
|
||||
callback_response = get_account_balance_callback_payload()
|
||||
process_balance_info(**callback_response)
|
||||
integration_request = frappe.get_doc("Integration Request", "AG_20200927_00007cdb1f9fb6494315")
|
||||
|
||||
# test integration request creation and successful update of the status on receiving callback response
|
||||
self.assertTrue(integration_request)
|
||||
self.assertEquals(integration_request.status, "Completed")
|
||||
|
||||
# test formatting of account balance received as string to json with appropriate currency symbol
|
||||
mpesa_doc.reload()
|
||||
self.assertEquals(mpesa_doc.account_balance, dumps({
|
||||
"Working Account": {
|
||||
"current_balance": "Sh 481,000.00",
|
||||
"available_balance": "Sh 481,000.00",
|
||||
"reserved_balance": "Sh 0.00",
|
||||
"uncleared_balance": "Sh 0.00"
|
||||
}
|
||||
}))
|
||||
|
||||
def test_processing_of_callback_payload(self):
|
||||
mpesa_doc = create_mpesa_settings(payment_gateway_name="Payment")
|
||||
mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
|
||||
frappe.db.set_value("Account", mpesa_account, "account_currency", "KES")
|
||||
|
||||
pos_invoice = create_pos_invoice(do_not_submit=1)
|
||||
pos_invoice.append("payments", {'mode_of_payment': 'Mpesa-Payment', 'account': mpesa_account, 'amount': 500})
|
||||
pos_invoice.contact_mobile = "093456543894"
|
||||
pos_invoice.currency = "KES"
|
||||
pos_invoice.save()
|
||||
|
||||
pr = pos_invoice.create_payment_request()
|
||||
# test payment request creation
|
||||
self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
|
||||
|
||||
callback_response = get_payment_callback_payload()
|
||||
verify_transaction(**callback_response)
|
||||
# test creation of integration request
|
||||
integration_request = frappe.get_doc("Integration Request", "ws_CO_061020201133231972")
|
||||
|
||||
# test integration request creation and successful update of the status on receiving callback response
|
||||
self.assertTrue(integration_request)
|
||||
self.assertEquals(integration_request.status, "Completed")
|
||||
|
||||
pos_invoice.reload()
|
||||
integration_request.reload()
|
||||
self.assertEquals(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
|
||||
self.assertEquals(integration_request.status, "Completed")
|
||||
|
||||
def create_mpesa_settings(payment_gateway_name="Express"):
|
||||
if frappe.db.exists("Mpesa Settings", payment_gateway_name):
|
||||
return frappe.get_doc("Mpesa Settings", payment_gateway_name)
|
||||
|
||||
doc = frappe.get_doc(dict(
|
||||
doctype="Mpesa Settings",
|
||||
payment_gateway_name=payment_gateway_name,
|
||||
consumer_key="5sMu9LVI1oS3oBGPJfh3JyvLHwZOdTKn",
|
||||
consumer_secret="VI1oS3oBGPJfh3JyvLHw",
|
||||
online_passkey="LVI1oS3oBGPJfh3JyvLHwZOd",
|
||||
till_number="174379"
|
||||
))
|
||||
|
||||
doc.insert(ignore_permissions=True)
|
||||
return doc
|
||||
|
||||
def get_test_account_balance_response():
|
||||
"""Response received after calling the account balance API."""
|
||||
return {
|
||||
"ResultType":0,
|
||||
"ResultCode":0,
|
||||
"ResultDesc":"The service request has been accepted successfully.",
|
||||
"OriginatorConversationID":"10816-694520-2",
|
||||
"ConversationID":"AG_20200927_00007cdb1f9fb6494315",
|
||||
"TransactionID":"LGR0000000",
|
||||
"ResultParameters":{
|
||||
"ResultParameter":[
|
||||
{
|
||||
"Key":"ReceiptNo",
|
||||
"Value":"LGR919G2AV"
|
||||
},
|
||||
{
|
||||
"Key":"Conversation ID",
|
||||
"Value":"AG_20170727_00004492b1b6d0078fbe"
|
||||
},
|
||||
{
|
||||
"Key":"FinalisedTime",
|
||||
"Value":20170727101415
|
||||
},
|
||||
{
|
||||
"Key":"Amount",
|
||||
"Value":10
|
||||
},
|
||||
{
|
||||
"Key":"TransactionStatus",
|
||||
"Value":"Completed"
|
||||
},
|
||||
{
|
||||
"Key":"ReasonType",
|
||||
"Value":"Salary Payment via API"
|
||||
},
|
||||
{
|
||||
"Key":"TransactionReason"
|
||||
},
|
||||
{
|
||||
"Key":"DebitPartyCharges",
|
||||
"Value":"Fee For B2C Payment|KES|33.00"
|
||||
},
|
||||
{
|
||||
"Key":"DebitAccountType",
|
||||
"Value":"Utility Account"
|
||||
},
|
||||
{
|
||||
"Key":"InitiatedTime",
|
||||
"Value":20170727101415
|
||||
},
|
||||
{
|
||||
"Key":"Originator Conversation ID",
|
||||
"Value":"19455-773836-1"
|
||||
},
|
||||
{
|
||||
"Key":"CreditPartyName",
|
||||
"Value":"254708374149 - John Doe"
|
||||
},
|
||||
{
|
||||
"Key":"DebitPartyName",
|
||||
"Value":"600134 - Safaricom157"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ReferenceData":{
|
||||
"ReferenceItem":{
|
||||
"Key":"Occasion",
|
||||
"Value":"aaaa"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def get_payment_request_response_payload():
|
||||
"""Response received after successfully calling the stk push process request API."""
|
||||
return {
|
||||
"MerchantRequestID": "8071-27184008-1",
|
||||
"CheckoutRequestID": "ws_CO_061020201133231972",
|
||||
"ResultCode": 0,
|
||||
"ResultDesc": "The service request is processed successfully.",
|
||||
"CallbackMetadata": {
|
||||
"Item": [
|
||||
{ "Name": "Amount", "Value": 500.0 },
|
||||
{ "Name": "MpesaReceiptNumber", "Value": "LGR7OWQX0R" },
|
||||
{ "Name": "TransactionDate", "Value": 20201006113336 },
|
||||
{ "Name": "PhoneNumber", "Value": 254723575670 }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_payment_callback_payload():
|
||||
"""Response received from the server as callback after calling the stkpush process request API."""
|
||||
return {
|
||||
"Body":{
|
||||
"stkCallback":{
|
||||
"MerchantRequestID":"19465-780693-1",
|
||||
"CheckoutRequestID":"ws_CO_061020201133231972",
|
||||
"ResultCode":0,
|
||||
"ResultDesc":"The service request is processed successfully.",
|
||||
"CallbackMetadata":{
|
||||
"Item":[
|
||||
{
|
||||
"Name":"Amount",
|
||||
"Value":500
|
||||
},
|
||||
{
|
||||
"Name":"MpesaReceiptNumber",
|
||||
"Value":"LGR7OWQX0R"
|
||||
},
|
||||
{
|
||||
"Name":"Balance"
|
||||
},
|
||||
{
|
||||
"Name":"TransactionDate",
|
||||
"Value":20170727154800
|
||||
},
|
||||
{
|
||||
"Name":"PhoneNumber",
|
||||
"Value":254721566839
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def get_account_balance_callback_payload():
|
||||
"""Response received from the server as callback after calling the account balance API."""
|
||||
return {
|
||||
"Result":{
|
||||
"ResultType": 0,
|
||||
"ResultCode": 0,
|
||||
"ResultDesc": "The service request is processed successfully.",
|
||||
"OriginatorConversationID": "16470-170099139-1",
|
||||
"ConversationID": "AG_20200927_00007cdb1f9fb6494315",
|
||||
"TransactionID": "OIR0000000",
|
||||
"ResultParameters": {
|
||||
"ResultParameter": [
|
||||
{
|
||||
"Key": "AccountBalance",
|
||||
"Value": "Working Account|KES|481000.00|481000.00|0.00|0.00"
|
||||
},
|
||||
{ "Key": "BOCompletedTime", "Value": 20200927234123 }
|
||||
]
|
||||
},
|
||||
"ReferenceData": {
|
||||
"ReferenceItem": {
|
||||
"Key": "QueueTimeoutURL",
|
||||
"Value": "https://internalsandbox.safaricom.co.ke/mpesa/abresults/v1/submit"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user