Skip to content

Commit

Permalink
Merge pull request #6 from navariltd/mpesa_dialog_form
Browse files Browse the repository at this point in the history
feat: fetch and reconcile invoices and mpesa draft payments
  • Loading branch information
emmanuel-mwendwa authored Oct 30, 2024
2 parents 97cec0b + 2902a24 commit e2f2d29
Show file tree
Hide file tree
Showing 23 changed files with 834 additions and 49 deletions.
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/frappe_mpsa_payments.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 29 additions & 23 deletions frappe_mpsa_payments/frappe_mpsa_payments/api/m_pesa_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,16 @@ def get_mpesa_mode_of_payment(company):
return modes_of_payment

@frappe.whitelist(allow_guest=True)
def get_mpesa_draft_c2b_payments(search_term):
def get_mpesa_draft_c2b_payments(
company,
full_name=None,
mode_of_payment=None,
from_date=None,
to_date=None,
):
fields = [
"name",
"transid",
"company",
"msisdn",
"full_name",
Expand All @@ -74,30 +81,26 @@ def get_mpesa_draft_c2b_payments(search_term):
"transamount",
]

filters = {"docstatus": 0}
filters = {"company": company, "docstatus": 0}
order_by="posting_date desc, posting_time desc"

if search_term:
payments_by_msisdn = frappe.get_all(
"Mpesa C2B Payment Register",
filters={"msisdn": ["like", f"%{search_term}%"], "docstatus": 0},
fields=fields,
order_by=order_by
)
payments_by_full_name = frappe.get_all(
"Mpesa C2B Payment Register",
filters={"full_name": ["like", f"%{search_term}%"], "docstatus": 0},
fields=fields,
order_by=order_by
)
if mode_of_payment:
filters["mode_of_payment"] = mode_of_payment

# Merge results from both queries
payments = payments_by_full_name + payments_by_msisdn
else:
# If search_term or status is not provided, return all payments with the given status
payments = frappe.get_all(
"Mpesa C2B Payment Register", filters=filters, fields=fields,order_by=order_by
)
if full_name:
filters["full_name"] = ["like", f"%{full_name}%"]

if from_date and to_date:
filters["posting_date"] = ["between", [from_date, to_date]]
elif from_date:
filters["posting_date"] = [">=", from_date]
elif to_date:
filters["posting_date"] = ["<=", to_date]

payments = frappe.get_all(
"Mpesa C2B Payment Register",
filters=filters, fields=fields,order_by=order_by
)

return payments

Expand Down Expand Up @@ -156,6 +159,7 @@ def submit_instant_mpesa_payment():
def process_mpesa_payment(mpesa_payment, customer, submit_payment=False):
try:
doc = frappe.get_doc("Mpesa C2B Payment Register", mpesa_payment)
print(f"Mpesa Payment: {doc}")
doc.customer = customer
# doc.mode_of_payment = mode_of_payment
#TODO: after testing, mode of payment
Expand All @@ -181,6 +185,8 @@ def get_payment_method(pos_profile):

def get_mode_of_payment(mpesa_doc):
business_short_code=mpesa_doc.businessshortcode
mode_of_payment = frappe.get_value("Mpesa C2B Payment Register URL", business_short_code, "mode_of_payment")
mode_of_payment = frappe.get_value("Mpesa C2B Payment Register URL", {"business_shortcode": business_short_code, "register_status": "Success"}, "mode_of_payment")
if mode_of_payment is None:
mode_of_payment = frappe.get_value("Mpesa C2B Payment Register URL", {"till_number": business_short_code, "register_status": "Success"}, "mode_of_payment")
return mode_of_payment

67 changes: 41 additions & 26 deletions frappe_mpsa_payments/frappe_mpsa_payments/api/payment_entry.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json

import frappe, erpnext
from frappe import _
Expand Down Expand Up @@ -285,13 +286,17 @@ def get_outstanding_invoices(
invoice_type=None,
common_filter=None,
posting_date=None,
from_date=None,
to_date=None,
min_outstanding=None,
max_outstanding=None,
accounting_dimensions=None,
vouchers=None,
limit=None,
voucher_no=None,
):
if invoice_type is None:
invoice_type = "Sales Invoice"

account=get_party_account("Customer", customer, company),
ple = qb.DocType("Payment Ledger Entry")
Expand All @@ -314,6 +319,12 @@ def get_outstanding_invoices(
common_filter.append(ple.account.isin(account))
common_filter.append(ple.party_type == "Customer")
common_filter.append(ple.party == customer)
if from_date and to_date:
common_filter.append(ple.posting_date.between(from_date, to_date))
elif from_date:
common_filter.append(ple.posting_date >= from_date)
elif to_date:
common_filter.append(ple.posting_date <= to_date)

ple_query = QueryPaymentLedger()
invoice_list = ple_query.get_voucher_outstandings(
Expand Down Expand Up @@ -482,10 +493,7 @@ def get_available_pos_profiles(company, currency):
)
return pos_profiles_list

def create_and_reconcile_payment_reconciliation(invoice_name, customer, company, payment_entries):
invoice = frappe.get_doc("Sales Invoice", invoice_name)
currency = invoice.get("currency")

def create_and_reconcile_payment_reconciliation(outstanding_invoices, customer, company, payment_entries):
reconcile_doc = frappe.new_doc("Payment Reconciliation")
reconcile_doc.party_type = "Customer"
reconcile_doc.party = customer
Expand All @@ -498,17 +506,20 @@ def create_and_reconcile_payment_reconciliation(invoice_name, customer, company,
"payments": [],
}

args["invoices"].append(
{
"invoice_type": "Sales Invoice",
"invoice_number": invoice.get("name"),
"invoice_date": invoice.get("posting_date"),
"amount": invoice.get("grand_total"),
"outstanding_amount": invoice.get("outstanding_amount"),
"currency": invoice.get("currency"),
"exchange_rate": 0,
}
)
for invoice in outstanding_invoices:
invoice_doc = frappe.get_doc("Sales Invoice", invoice)
args["invoices"].append(
{
"invoice_type": "Sales Invoice",
"invoice_number": invoice_doc.get("name"),
"invoice_date": invoice_doc.get("posting_date"),
"amount": invoice_doc.get("grand_total"),
"outstanding_amount": invoice_doc.get("outstanding_amount"),
"currency": invoice_doc.get("currency"),
"exchange_rate": 0,
}
)


for payment_entry in payment_entries:
payment_entry_doc = frappe.get_doc("Payment Entry", payment_entry)
Expand All @@ -530,20 +541,24 @@ def create_and_reconcile_payment_reconciliation(invoice_name, customer, company,
frappe.db.commit()

@frappe.whitelist()
def process_mpesa_c2b_reconciliation():
mpesa_transaction = frappe.form_dict.get("mpesa_name")
invoice_name = frappe.form_dict.get("invoice_name")
invoice = frappe.get_doc("Sales Invoice", invoice_name)
customer = invoice.get("customer")
company = invoice.get("company")
def process_mpesa_c2b_reconciliation(mpesa_names, invoice_names):
if isinstance(mpesa_names, str):
mpesa_names = json.loads(mpesa_names)
if isinstance(invoice_names, str):
invoice_names = json.loads(invoice_names)

# TODO: after testing, withdraw this static method of payment
mode_of_payment = "Mpesa-Test"
if not invoice_names:
frappe.throw(_("No invoices provided."))

payment_entry = submit_mpesa_payment(mpesa_transaction, customer)
payment_entries = [payment_entry.get("name")]
first_invoice_name = invoice_names[0]
first_invoice = frappe.get_doc("Sales Invoice", first_invoice_name)
customer = first_invoice.get("customer")
company = first_invoice.get("company")

create_and_reconcile_payment_reconciliation(invoice_name, customer, company, payment_entries)
payment_entries = [submit_mpesa_payment(mpesa_name, customer).get("name") for mpesa_name in
mpesa_names]

create_and_reconcile_payment_reconciliation(invoice_names, customer, company, payment_entries)


@frappe.whitelist()
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2024-10-17 07:33:08.666932",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"payment_id",
"full_name",
"column_break_fnjs",
"date",
"amount"
],
"fields": [
{
"fieldname": "payment_id",
"fieldtype": "Link",
"in_list_view": 1,
"in_preview": 1,
"in_standard_filter": 1,
"label": "Payment ID",
"options": "Mpesa C2B Payment Register"
},
{
"fieldname": "full_name",
"fieldtype": "Data",
"in_list_view": 1,
"in_preview": 1,
"in_standard_filter": 1,
"label": "Full Name"
},
{
"fieldname": "date",
"fieldtype": "Date",
"in_list_view": 1,
"in_preview": 1,
"in_standard_filter": 1,
"label": "Date"
},
{
"fieldname": "amount",
"fieldtype": "Currency",
"in_list_view": 1,
"in_preview": 1,
"in_standard_filter": 1,
"label": "Amount"
},
{
"fieldname": "column_break_fnjs",
"fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"is_virtual": 1,
"istable": 1,
"links": [],
"modified": "2024-10-17 07:35:16.568396",
"modified_by": "Administrator",
"module": "Frappe Mpsa Payments",
"name": "Mpesa Draft Payments",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright (c) 2024, Navari Limited and contributors
# For license information, please see license.txt

# import frappe
from frappe.model.document import Document


class MpesaDraftPayments(Document):

def db_insert(self, *args, **kwargs):
pass

def load_from_db(self):
pass

def db_update(self):
pass
def delete(self):
pass

@staticmethod
def get_list(args):
pass

@staticmethod
def get_count(args):
pass

@staticmethod
def get_stats(args):
pass

Empty file.
Loading

0 comments on commit e2f2d29

Please sign in to comment.