From 47345e81a1342c3a6c904c66368460b18dd2816a Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 15 Aug 2023 05:17:01 +0530 Subject: [PATCH 1/2] perf: pull latest details only for referenced vouchers (cherry picked from commit deb0d7129438ff7966e1e50f5f7eb0a78e2fdb49) # Conflicts: # erpnext/accounts/doctype/payment_entry/payment_entry.py --- .../doctype/payment_entry/payment_entry.py | 96 ++++++++++++++++--- erpnext/accounts/utils.py | 2 + 2 files changed, 85 insertions(+), 13 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 379903dade3f..35a0e85a37da 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -185,6 +185,7 @@ def term_based_allocation_enabled_for_reference( return False def validate_allocated_amount_with_latest_data(self): +<<<<<<< HEAD latest_references = get_outstanding_reference_documents( { "posting_date": self.posting_date, @@ -197,16 +198,36 @@ def validate_allocated_amount_with_latest_data(self): "get_orders_to_be_billed": True, } ) +======= + if self.references: + uniq_vouchers = set([(x.reference_doctype, x.reference_name) for x in self.references]) + vouchers = [frappe._dict({"voucher_type": x[0], "voucher_no": x[1]}) for x in uniq_vouchers] + latest_references = get_outstanding_reference_documents( + { + "posting_date": self.posting_date, + "company": self.company, + "party_type": self.party_type, + "payment_type": self.payment_type, + "party": self.party, + "party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to, + "get_outstanding_invoices": True, + "get_orders_to_be_billed": True, + "vouchers": vouchers, + }, + validate=True, + ) +>>>>>>> deb0d71294 (perf: pull latest details only for referenced vouchers) - # Group latest_references by (voucher_type, voucher_no) - latest_lookup = {} - for d in latest_references: - d = frappe._dict(d) - latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d + # Group latest_references by (voucher_type, voucher_no) + latest_lookup = {} + for d in latest_references: + d = frappe._dict(d) + latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d - for idx, d in enumerate(self.get("references"), start=1): - latest = latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict() + for idx, d in enumerate(self.get("references"), start=1): + latest = latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict() +<<<<<<< HEAD # If term based allocation is enabled, throw if ( d.payment_term is None or d.payment_term == "" @@ -254,15 +275,63 @@ def validate_allocated_amount_with_latest_data(self): "Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}" ).format( d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term +======= + # If term based allocation is enabled, throw + if ( + d.payment_term is None or d.payment_term == "" + ) and self.term_based_allocation_enabled_for_reference( + d.reference_doctype, d.reference_name + ): + frappe.throw( + _( + "{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section" + ).format(frappe.bold(d.reference_name), frappe.bold(idx)) +>>>>>>> deb0d71294 (perf: pull latest details only for referenced vouchers) ) - ) - if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount): - frappe.throw(fail_message.format(d.idx)) + # if no payment template is used by invoice and has a custom term(no `payment_term`), then invoice outstanding will be in 'None' key + latest = latest.get(d.payment_term) or latest.get(None) - # Check for negative outstanding invoices as well - if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount): - frappe.throw(fail_message.format(d.idx)) + # The reference has already been fully paid + if not latest: + frappe.throw( + _("{0} {1} has already been fully paid.").format(_(d.reference_doctype), d.reference_name) + ) + # The reference has already been partly paid + elif latest.outstanding_amount < latest.invoice_amount and flt( + d.outstanding_amount, d.precision("outstanding_amount") + ) != flt(latest.outstanding_amount, d.precision("outstanding_amount")): + frappe.throw( + _( + "{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts." + ).format(_(d.reference_doctype), d.reference_name) + ) + + fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.") + + if ( + d.payment_term + and ( + (flt(d.allocated_amount)) > 0 + and latest.payment_term_outstanding + and (flt(d.allocated_amount) > flt(latest.payment_term_outstanding)) + ) + and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name) + ): + frappe.throw( + _( + "Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}" + ).format( + d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term + ) + ) + + if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount): + frappe.throw(fail_message.format(d.idx)) + + # Check for negative outstanding invoices as well + if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount): + frappe.throw(fail_message.format(d.idx)) def delink_advance_entry_references(self): for reference in self.references: @@ -1463,6 +1532,7 @@ def get_outstanding_reference_documents(args): min_outstanding=args.get("outstanding_amt_greater_than"), max_outstanding=args.get("outstanding_amt_less_than"), accounting_dimensions=accounting_dimensions_filter, + vouchers=args.get("vouchers") or None, ) outstanding_invoices = split_invoices_based_on_payment_terms( diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 3e06a36e67ed..2df3387b83e3 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -884,6 +884,7 @@ def get_outstanding_invoices( min_outstanding=None, max_outstanding=None, accounting_dimensions=None, + vouchers=None, ): ple = qb.DocType("Payment Ledger Entry") @@ -909,6 +910,7 @@ def get_outstanding_invoices( ple_query = QueryPaymentLedger() invoice_list = ple_query.get_voucher_outstandings( + vouchers=vouchers, common_filter=common_filter, posting_date=posting_date, min_outstanding=min_outstanding, From 3f33d4cf763a46d111c6084f8a61c940c0d72496 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 17 Aug 2023 09:21:11 +0530 Subject: [PATCH 2/2] chore: resolve conflicts --- .../doctype/payment_entry/payment_entry.py | 68 +------------------ 1 file changed, 1 insertion(+), 67 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 35a0e85a37da..c94e02325131 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -185,20 +185,6 @@ def term_based_allocation_enabled_for_reference( return False def validate_allocated_amount_with_latest_data(self): -<<<<<<< HEAD - latest_references = get_outstanding_reference_documents( - { - "posting_date": self.posting_date, - "company": self.company, - "party_type": self.party_type, - "payment_type": self.payment_type, - "party": self.party, - "party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to, - "get_outstanding_invoices": True, - "get_orders_to_be_billed": True, - } - ) -======= if self.references: uniq_vouchers = set([(x.reference_doctype, x.reference_name) for x in self.references]) vouchers = [frappe._dict({"voucher_type": x[0], "voucher_no": x[1]}) for x in uniq_vouchers] @@ -213,10 +199,8 @@ def validate_allocated_amount_with_latest_data(self): "get_outstanding_invoices": True, "get_orders_to_be_billed": True, "vouchers": vouchers, - }, - validate=True, + } ) ->>>>>>> deb0d71294 (perf: pull latest details only for referenced vouchers) # Group latest_references by (voucher_type, voucher_no) latest_lookup = {} @@ -227,55 +211,6 @@ def validate_allocated_amount_with_latest_data(self): for idx, d in enumerate(self.get("references"), start=1): latest = latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict() -<<<<<<< HEAD - # If term based allocation is enabled, throw - if ( - d.payment_term is None or d.payment_term == "" - ) and self.term_based_allocation_enabled_for_reference( - d.reference_doctype, d.reference_name - ): - frappe.throw( - _( - "{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section" - ).format(frappe.bold(d.reference_name), frappe.bold(idx)) - ) - - # if no payment template is used by invoice and has a custom term(no `payment_term`), then invoice outstanding will be in 'None' key - latest = latest.get(d.payment_term) or latest.get(None) - - # The reference has already been fully paid - if not latest: - frappe.throw( - _("{0} {1} has already been fully paid.").format(_(d.reference_doctype), d.reference_name) - ) - # The reference has already been partly paid - elif latest.outstanding_amount < latest.invoice_amount and flt( - d.outstanding_amount, d.precision("outstanding_amount") - ) != flt(latest.outstanding_amount, d.precision("outstanding_amount")): - - frappe.throw( - _( - "{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts." - ).format(_(d.reference_doctype), d.reference_name) - ) - - fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.") - - if ( - d.payment_term - and ( - (flt(d.allocated_amount)) > 0 - and latest.payment_term_outstanding - and (flt(d.allocated_amount) > flt(latest.payment_term_outstanding)) - ) - and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name) - ): - frappe.throw( - _( - "Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}" - ).format( - d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term -======= # If term based allocation is enabled, throw if ( d.payment_term is None or d.payment_term == "" @@ -286,7 +221,6 @@ def validate_allocated_amount_with_latest_data(self): _( "{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section" ).format(frappe.bold(d.reference_name), frappe.bold(idx)) ->>>>>>> deb0d71294 (perf: pull latest details only for referenced vouchers) ) # if no payment template is used by invoice and has a custom term(no `payment_term`), then invoice outstanding will be in 'None' key