Merge pull request #36778 from frappe/mergify/bp/version-14-hotfix/pr-36650

perf: improve responsiveness of payment reconciliation tool (backport #36650)
This commit is contained in:
ruthra kumar
2023-08-23 15:08:47 +05:30
committed by GitHub
4 changed files with 65 additions and 9 deletions

View File

@@ -151,6 +151,15 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
this.frm.refresh(); this.frm.refresh();
} }
invoice_name() {
this.frm.trigger("get_unreconciled_entries");
}
payment_name() {
this.frm.trigger("get_unreconciled_entries");
}
clear_child_tables() { clear_child_tables() {
this.frm.clear_table("invoices"); this.frm.clear_table("invoices");
this.frm.clear_table("payments"); this.frm.clear_table("payments");

View File

@@ -26,8 +26,10 @@
"bank_cash_account", "bank_cash_account",
"cost_center", "cost_center",
"sec_break1", "sec_break1",
"invoice_name",
"invoices", "invoices",
"column_break_15", "column_break_15",
"payment_name",
"payments", "payments",
"sec_break2", "sec_break2",
"allocation" "allocation"
@@ -136,6 +138,7 @@
"label": "Minimum Invoice Amount" "label": "Minimum Invoice Amount"
}, },
{ {
"default": "50",
"description": "System will fetch all the entries if limit value is zero.", "description": "System will fetch all the entries if limit value is zero.",
"fieldname": "invoice_limit", "fieldname": "invoice_limit",
"fieldtype": "Int", "fieldtype": "Int",
@@ -166,6 +169,7 @@
"label": "Maximum Payment Amount" "label": "Maximum Payment Amount"
}, },
{ {
"default": "50",
"description": "System will fetch all the entries if limit value is zero.", "description": "System will fetch all the entries if limit value is zero.",
"fieldname": "payment_limit", "fieldname": "payment_limit",
"fieldtype": "Int", "fieldtype": "Int",
@@ -185,13 +189,23 @@
"fieldtype": "Link", "fieldtype": "Link",
"label": "Cost Center", "label": "Cost Center",
"options": "Cost Center" "options": "Cost Center"
},
{
"fieldname": "invoice_name",
"fieldtype": "Data",
"label": "Filter on Invoice"
},
{
"fieldname": "payment_name",
"fieldtype": "Data",
"label": "Filter on Payment"
} }
], ],
"hide_toolbar": 1, "hide_toolbar": 1,
"icon": "icon-resize-horizontal", "icon": "icon-resize-horizontal",
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2022-04-29 15:37:10.246831", "modified": "2023-08-15 05:35:50.109290",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Reconciliation", "name": "Payment Reconciliation",
@@ -218,4 +232,4 @@
"sort_order": "DESC", "sort_order": "DESC",
"states": [], "states": [],
"track_changes": 1 "track_changes": 1
} }

View File

@@ -5,6 +5,7 @@
import frappe import frappe
from frappe import _, msgprint, qb from frappe import _, msgprint, qb
from frappe.model.document import Document from frappe.model.document import Document
from frappe.query_builder import Criterion
from frappe.query_builder.custom import ConstantColumn from frappe.query_builder.custom import ConstantColumn
from frappe.utils import flt, fmt_money, get_link_to_form, getdate, nowdate, today from frappe.utils import flt, fmt_money, get_link_to_form, getdate, nowdate, today
@@ -58,6 +59,9 @@ class PaymentReconciliation(Document):
def get_payment_entries(self): def get_payment_entries(self):
order_doctype = "Sales Order" if self.party_type == "Customer" else "Purchase Order" order_doctype = "Sales Order" if self.party_type == "Customer" else "Purchase Order"
condition = self.get_conditions(get_payments=True) condition = self.get_conditions(get_payments=True)
if self.payment_name:
condition += "name like '%%{0}%%'".format(self.payment_name)
payment_entries = get_advance_payment_entries( payment_entries = get_advance_payment_entries(
self.party_type, self.party_type,
self.party, self.party,
@@ -73,6 +77,9 @@ class PaymentReconciliation(Document):
def get_jv_entries(self): def get_jv_entries(self):
condition = self.get_conditions() condition = self.get_conditions()
if self.payment_name:
condition += f" and t1.name like '%%{self.payment_name}%%'"
if self.get("cost_center"): if self.get("cost_center"):
condition += f" and t2.cost_center = '{self.cost_center}' " condition += f" and t2.cost_center = '{self.cost_center}' "
@@ -130,6 +137,15 @@ class PaymentReconciliation(Document):
def get_return_invoices(self): def get_return_invoices(self):
voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice" voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
doc = qb.DocType(voucher_type) doc = qb.DocType(voucher_type)
conditions = []
conditions.append(doc.docstatus == 1)
conditions.append(doc[frappe.scrub(self.party_type)] == self.party)
conditions.append(doc.is_return == 1)
if self.payment_name:
conditions.append(doc.name.like(f"%{self.payment_name}%"))
self.return_invoices = ( self.return_invoices = (
qb.from_(doc) qb.from_(doc)
.select( .select(
@@ -137,11 +153,7 @@ class PaymentReconciliation(Document):
doc.name.as_("voucher_no"), doc.name.as_("voucher_no"),
doc.return_against, doc.return_against,
) )
.where( .where(Criterion.all(conditions))
(doc.docstatus == 1)
& (doc[frappe.scrub(self.party_type)] == self.party)
& (doc.is_return == 1)
)
.run(as_dict=True) .run(as_dict=True)
) )
@@ -210,6 +222,8 @@ class PaymentReconciliation(Document):
min_outstanding=self.minimum_invoice_amount if self.minimum_invoice_amount else None, min_outstanding=self.minimum_invoice_amount if self.minimum_invoice_amount else None,
max_outstanding=self.maximum_invoice_amount if self.maximum_invoice_amount else None, max_outstanding=self.maximum_invoice_amount if self.maximum_invoice_amount else None,
accounting_dimensions=self.accounting_dimension_filter_conditions, accounting_dimensions=self.accounting_dimension_filter_conditions,
limit=self.invoice_limit,
voucher_no=self.invoice_name,
) )
cr_dr_notes = ( cr_dr_notes = (

View File

@@ -884,7 +884,9 @@ def get_outstanding_invoices(
min_outstanding=None, min_outstanding=None,
max_outstanding=None, max_outstanding=None,
accounting_dimensions=None, accounting_dimensions=None,
vouchers=None, vouchers=None, # list of dicts [{'voucher_type': '', 'voucher_no': ''}] for filtering
limit=None, # passed by reconciliation tool
voucher_no=None, # filter passed by reconciliation tool
): ):
ple = qb.DocType("Payment Ledger Entry") ple = qb.DocType("Payment Ledger Entry")
@@ -917,6 +919,8 @@ def get_outstanding_invoices(
max_outstanding=max_outstanding, max_outstanding=max_outstanding,
get_invoices=True, get_invoices=True,
accounting_dimensions=accounting_dimensions or [], accounting_dimensions=accounting_dimensions or [],
limit=limit,
voucher_no=voucher_no,
) )
for d in invoice_list: for d in invoice_list:
@@ -1648,12 +1652,13 @@ class QueryPaymentLedger(object):
self.voucher_posting_date = [] self.voucher_posting_date = []
self.min_outstanding = None self.min_outstanding = None
self.max_outstanding = None self.max_outstanding = None
self.limit = self.voucher_no = None
def reset(self): def reset(self):
# clear filters # clear filters
self.vouchers.clear() self.vouchers.clear()
self.common_filter.clear() self.common_filter.clear()
self.min_outstanding = self.max_outstanding = None self.min_outstanding = self.max_outstanding = self.limit = None
# clear result # clear result
self.voucher_outstandings.clear() self.voucher_outstandings.clear()
@@ -1667,6 +1672,7 @@ class QueryPaymentLedger(object):
filter_on_voucher_no = [] filter_on_voucher_no = []
filter_on_against_voucher_no = [] filter_on_against_voucher_no = []
if self.vouchers: if self.vouchers:
voucher_types = set([x.voucher_type for x in self.vouchers]) voucher_types = set([x.voucher_type for x in self.vouchers])
voucher_nos = set([x.voucher_no for x in self.vouchers]) voucher_nos = set([x.voucher_no for x in self.vouchers])
@@ -1677,6 +1683,10 @@ class QueryPaymentLedger(object):
filter_on_against_voucher_no.append(ple.against_voucher_type.isin(voucher_types)) filter_on_against_voucher_no.append(ple.against_voucher_type.isin(voucher_types))
filter_on_against_voucher_no.append(ple.against_voucher_no.isin(voucher_nos)) filter_on_against_voucher_no.append(ple.against_voucher_no.isin(voucher_nos))
if self.voucher_no:
filter_on_voucher_no.append(ple.voucher_no.like(f"%{self.voucher_no}%"))
filter_on_against_voucher_no.append(ple.against_voucher_no.like(f"%{self.voucher_no}%"))
# build outstanding amount filter # build outstanding amount filter
filter_on_outstanding_amount = [] filter_on_outstanding_amount = []
if self.min_outstanding: if self.min_outstanding:
@@ -1792,6 +1802,11 @@ class QueryPaymentLedger(object):
) )
) )
if self.limit:
self.cte_query_voucher_amount_and_outstanding = (
self.cte_query_voucher_amount_and_outstanding.limit(self.limit)
)
# execute SQL # execute SQL
self.voucher_outstandings = self.cte_query_voucher_amount_and_outstanding.run(as_dict=True) self.voucher_outstandings = self.cte_query_voucher_amount_and_outstanding.run(as_dict=True)
@@ -1805,6 +1820,8 @@ class QueryPaymentLedger(object):
get_payments=False, get_payments=False,
get_invoices=False, get_invoices=False,
accounting_dimensions=None, accounting_dimensions=None,
limit=None,
voucher_no=None,
): ):
""" """
Fetch voucher amount and outstanding amount from Payment Ledger using Database CTE Fetch voucher amount and outstanding amount from Payment Ledger using Database CTE
@@ -1826,6 +1843,8 @@ class QueryPaymentLedger(object):
self.max_outstanding = max_outstanding self.max_outstanding = max_outstanding
self.get_payments = get_payments self.get_payments = get_payments
self.get_invoices = get_invoices self.get_invoices = get_invoices
self.limit = limit
self.voucher_no = voucher_no
self.query_for_outstanding() self.query_for_outstanding()
return self.voucher_outstandings return self.voucher_outstandings