Skip to content

Commit

Permalink
Merge pull request #13 from navariltd/transaction_status
Browse files Browse the repository at this point in the history
refactor: remove transaction_status button from mpesa_c2b_payment_register to mpesa_settings
  • Loading branch information
emmanuel-mwendwa authored Feb 18, 2025
2 parents ded5c2f + e9cc772 commit 79e97ee
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 144 deletions.
Original file line number Diff line number Diff line change
@@ -1,41 +1,8 @@
// Copyright (c) 2024, Navari Limited and contributors
// For license information, please see license.txt

frappe.ui.form.on("Mpesa C2B Payment Register URL", {
refresh(frm) {
frm.add_custom_button("Check Transaction Status", () => {
frappe.prompt(
[
{
label: "Transaction ID",
fieldname: "transaction_id",
fieldtype: "Data",
reqd: 1
},
{
label: "Remarks",
fieldname: "remarks",
fieldtype: "Small Text",
}
],
(values) => {
frappe.call({
method: "trigger_transaction_status",
doc: frm.doc,
args: {
transaction_id: values.transaction_id,
remarks: values.remarks
},
callback: (r) => {
if (r.message) {
frappe.msgprint(r.message)
}
}
});
},
__("Transaction Status Query"),
__("Submit")
);
});
},
});
// frappe.ui.form.on("Mpesa C2B Payment Register URL", {
// refresh(frm) {

// },
// });
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from frappe.utils import get_request_site_address
from frappe_mpsa_payments.frappe_mpsa_payments.api.m_pesa_api import get_token
from ..mpesa_settings.mpesa_connector import MpesaConnector
from frappe_mpsa_payments.utils.encoding_initiator_password import generate_security_credential


class MpesaC2BPaymentRegisterURL(Document):
def validate(self):
Expand Down Expand Up @@ -75,46 +75,3 @@ def validate(self):
except requests.exceptions.RequestException as err:
# Handle other exceptions
frappe.msgprint(f"Request Exception: {err}")

@frappe.whitelist()
def trigger_transaction_status(self, transaction_id, remarks="OK"):

try:

settings = frappe.get_doc("Mpesa Settings", self.mpesa_settings)

# Retrieve the public certificate path from the Mpesa Public Key Certificate doctype
certificate_type = "sandbox_certificate" if settings.sandbox else "production_certificate"
public_cert_path = frappe.db.get_single_value("Mpesa Public Key Certificate", certificate_type)

if not public_cert_path:
frappe.throw(f"Certificate file for {certificate_type} not found in Mpesa Public Key Certificate doctype.")

# Generate security credential
security_credential = generate_security_credential(settings.get_password("initiator_password"), public_cert_path)

queue_timeout_url = get_request_site_address(True) + "/api/method/frappe_mpsa_payments.frappe_mpsa_payments.api.m_pesa_api.handle_queue_timeout"

result_url = get_request_site_address(True) + "/api/method/frappe_mpsa_payments.frappe_mpsa_payments.api.m_pesa_api.handle_transaction_status_result"

connector = MpesaConnector(
env="production" if not settings.sandbox else "sandbox",
app_key=settings.consumer_key,
app_secret=settings.get_password("consumer_secret")
)

response = connector.transaction_status(
initiator=settings.initiator_name,
security_credential=security_credential,
transaction_id=transaction_id,
party_a=settings.business_shortcode if not settings.sandbox else settings.till_number,
identifier_type=4, # Assuming Organization Short Code
remarks=remarks,
occasion="",
queue_timeout_url=queue_timeout_url,
result_url=result_url
)
return response
except Exception as e:
frappe.log_error(title="Mpesa Transaction Status Error", message=str(e))
return {"status": "error", "message": str(e)}
Original file line number Diff line number Diff line change
@@ -1,61 +1,60 @@
{
"actions": [],
"creation": "2024-07-09 15:06:17.747970",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"certificates_section",
"sandbox_certificate",
"column_break_xshs",
"production_certificate"
],
"fields": [
{
"fieldname": "sandbox_certificate",
"fieldtype": "Attach",
"in_list_view": 1,
"label": "Sandbox Certificate",
"reqd": 1
},
{
"fieldname": "column_break_xshs",
"fieldtype": "Column Break"
},
{
"fieldname": "production_certificate",
"fieldtype": "Attach",
"in_list_view": 1,
"label": "Production Certificate",
"reqd": 1
},
{
"fieldname": "certificates_section",
"fieldtype": "Section Break",
"label": "Certificates"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2024-07-09 15:08:38.962831",
"modified_by": "Administrator",
"module": "Frappe Mpsa Payments",
"name": "Mpesa Public Key Certificate",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
"actions": [],
"creation": "2024-07-09 15:06:17.747970",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"certificates_section",
"sandbox_certificate",
"column_break_xshs",
"production_certificate"
],
"fields": [
{
"fieldname": "sandbox_certificate",
"fieldtype": "Attach",
"in_list_view": 1,
"label": "Sandbox Certificate"
},
{
"fieldname": "column_break_xshs",
"fieldtype": "Column Break"
},
{
"fieldname": "production_certificate",
"fieldtype": "Attach",
"in_list_view": 1,
"label": "Production Certificate",
"reqd": 1
},
{
"fieldname": "certificates_section",
"fieldtype": "Section Break",
"label": "Certificates"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-02-17 09:02:23.002707",
"modified_by": "Administrator",
"module": "Frappe Mpsa Payments",
"name": "Mpesa Public Key Certificate",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,56 @@ frappe.ui.form.on('Mpesa Settings', {
})
);
frm.dashboard.show();
},

check_transaction_status: function(frm) {
if (!frm.doc.initiator_name && !frm.doc.initiator_password) {
frappe.throw(__("Please set the initiator name and the initiator password"));
}
frappe.clear_cache;
frappe.prompt(
[
{
label: "Transaction ID",
fieldname: "transaction_id",
fieldtype: "Data",
reqd: 1
},
{
label: "Remarks",
fieldname: "remarks",
fieldtype: "Small Text",
}
],
(values) => {
frappe.call({
method: "frappe_mpsa_payments.frappe_mpsa_payments.doctype.mpesa_settings.mpesa_settings.trigger_transaction_status",
args: {
mpesa_settings: frm.doc.name,
transaction_id: values.transaction_id,
remarks: values.remarks
},
callback: (r) => {
if (r.message) {
if (r.message.ResponseCode === "0") {
frappe.msgprint({
message: __("Transaction Status: {0}", [r.message.ResponseDescription]),
title: "Success",
indicator: "green",
});
} else {
frappe.msgprint({
message: r.message.errorCode + ": " + r.message.errorMessage,
title: "Error",
indicator: "red",
});
}
}
}
});
},
__("Transaction Status Query"),
__("Submit")
);
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"business_shortcode",
"online_passkey",
"get_account_balance",
"check_transaction_status",
"account_balance"
],
"fields": [
Expand Down Expand Up @@ -126,10 +127,15 @@
"fieldname": "initiator_password",
"fieldtype": "Password",
"label": "Initiator Password"
},
{
"fieldname": "check_transaction_status",
"fieldtype": "Button",
"label": "Check Transaction Status"
}
],
"links": [],
"modified": "2025-01-30 10:57:43.104261",
"modified": "2025-02-18 11:17:04.338605",
"modified_by": "Administrator",
"module": "Frappe Mpsa Payments",
"name": "Mpesa Settings",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import base64
from json import dumps, loads
from typing import Any
from urllib.parse import urlparse

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
Expand All @@ -15,13 +16,14 @@
from frappe import _, get_single
from frappe.integrations.utils import create_request_log
from frappe.model.document import Document
from frappe.utils import call_hook_method, fmt_money, get_request_site_address
from frappe.utils import call_hook_method, fmt_money, get_request_site_address, get_link_to_form
from frappe.utils.file_manager import get_file_path

from ....utils.doctype_names import PUBLIC_CERTIFICATES_DOCTYPE
from ....utils.utils import erpnext_app_import_guard
from .mpesa_connector import MpesaConnector
from .mpesa_custom_fields import create_custom_pos_fields
from frappe_mpsa_payments.utils.encoding_initiator_password import generate_security_credential


class MpesaSettings(Document):
Expand Down Expand Up @@ -390,3 +392,49 @@ def create_mode_of_payment(gateway: str, payment_type: str = "General") -> Docum
return mode_of_payment

return frappe.get_doc("Mode of Payment", mode_of_payment)

@frappe.whitelist()
def trigger_transaction_status(mpesa_settings, transaction_id, remarks="OK"):

try:

settings = frappe.get_doc("Mpesa Settings", mpesa_settings)

site_address = get_request_site_address(True)
parsed_url = urlparse(site_address)
site_url = f"{parsed_url.scheme}://{parsed_url.hostname}"

# Retrieve the public certificate path from the Mpesa Public Key Certificate doctype
certificate_type = "sandbox_certificate" if settings.sandbox else "production_certificate"
public_cert_path = frappe.db.get_single_value("Mpesa Public Key Certificate", certificate_type)

if not public_cert_path:
frappe.throw(f"Certificate file for {certificate_type} not found in {get_link_to_form(r'Mpesa Public Key Certificate', r'Mpesa Public Key Certificate')} doctype.")

# Generate security credential
security_credential = generate_security_credential(settings.get_password("initiator_password"), public_cert_path)

queue_timeout_url = site_url + "/api/method/frappe_mpsa_payments.frappe_mpsa_payments.api.m_pesa_api.handle_queue_timeout"
result_url = site_url + "/api/method/frappe_mpsa_payments.frappe_mpsa_payments.api.m_pesa_api.handle_transaction_status_result"

connector = MpesaConnector(
env="production" if not settings.sandbox else "sandbox",
app_key=settings.consumer_key,
app_secret=settings.get_password("consumer_secret")
)

response = connector.transaction_status(
initiator=settings.initiator_name,
security_credential=security_credential,
transaction_id=transaction_id,
party_a=settings.business_shortcode if not settings.sandbox else settings.till_number,
identifier_type=4, # Assuming Organization Short Code
remarks=remarks,
occasion="",
queue_timeout_url=queue_timeout_url,
result_url=result_url
)
return response
except Exception as e:
frappe.log_error(title="Mpesa Transaction Status Error", message=str(e))
return {"status": "error", "message": str(e)}
Loading

0 comments on commit 79e97ee

Please sign in to comment.