Merge pull request #36181 from ruthra-kumar/fix_broken_overallocation_validation_on_multi_term_payment_against_invoice

fix: broken overallocation validation in payment entry
This commit is contained in:
ruthra kumar 2023-07-19 10:46:41 +05:30 committed by GitHub
commit bccfd22fc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -226,10 +226,12 @@ class PaymentEntry(AccountsController):
latest_lookup = {} latest_lookup = {}
for d in latest_references: for d in latest_references:
d = frappe._dict(d) d = frappe._dict(d)
latest_lookup.update({(d.voucher_type, d.voucher_no): d}) latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d
for d in self.get("references"): for d in self.get("references"):
latest = latest_lookup.get((d.reference_doctype, d.reference_name)) latest = (latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict()).get(
d.payment_term
)
# The reference has already been fully paid # The reference has already been fully paid
if not latest: if not latest:
@ -251,6 +253,18 @@ class PaymentEntry(AccountsController):
if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount): if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
frappe.throw(fail_message.format(d.idx)) frappe.throw(fail_message.format(d.idx))
if d.payment_term and (
(flt(d.allocated_amount)) > 0
and flt(d.allocated_amount) > flt(latest.payment_term_outstanding)
):
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
)
)
# Check for negative outstanding invoices as well # Check for negative outstanding invoices as well
if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount): if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount):
frappe.throw(fail_message.format(d.idx)) frappe.throw(fail_message.format(d.idx))
@ -1500,7 +1514,9 @@ def get_outstanding_reference_documents(args, validate=False):
accounting_dimensions=accounting_dimensions_filter, accounting_dimensions=accounting_dimensions_filter,
) )
outstanding_invoices = split_invoices_based_on_payment_terms(outstanding_invoices) outstanding_invoices = split_invoices_based_on_payment_terms(
outstanding_invoices, args.get("company")
)
for d in outstanding_invoices: for d in outstanding_invoices:
d["exchange_rate"] = 1 d["exchange_rate"] = 1
@ -1560,8 +1576,27 @@ def get_outstanding_reference_documents(args, validate=False):
return data return data
def split_invoices_based_on_payment_terms(outstanding_invoices): def split_invoices_based_on_payment_terms(outstanding_invoices, company):
invoice_ref_based_on_payment_terms = {} invoice_ref_based_on_payment_terms = {}
company_currency = (
frappe.db.get_value("Company", company, "default_currency") if company else None
)
exc_rates = frappe._dict()
for doctype in ["Sales Invoice", "Purchase Invoice"]:
invoices = [x.voucher_no for x in outstanding_invoices if x.voucher_type == doctype]
for x in frappe.db.get_all(
doctype,
filters={"name": ["in", invoices]},
fields=["name", "currency", "conversion_rate", "party_account_currency"],
):
exc_rates[x.name] = frappe._dict(
conversion_rate=x.conversion_rate,
currency=x.currency,
party_account_currency=x.party_account_currency,
company_currency=company_currency,
)
for idx, d in enumerate(outstanding_invoices): for idx, d in enumerate(outstanding_invoices):
if d.voucher_type in ["Sales Invoice", "Purchase Invoice"]: if d.voucher_type in ["Sales Invoice", "Purchase Invoice"]:
payment_term_template = frappe.db.get_value( payment_term_template = frappe.db.get_value(
@ -1578,6 +1613,14 @@ def split_invoices_based_on_payment_terms(outstanding_invoices):
for payment_term in payment_schedule: for payment_term in payment_schedule:
if payment_term.outstanding > 0.1: if payment_term.outstanding > 0.1:
doc_details = exc_rates.get(payment_term.parent, None)
is_multi_currency_acc = (doc_details.currency != doc_details.company_currency) and (
doc_details.party_account_currency != doc_details.company_currency
)
payment_term_outstanding = flt(payment_term.outstanding)
if not is_multi_currency_acc:
payment_term_outstanding = doc_details.conversion_rate * flt(payment_term.outstanding)
invoice_ref_based_on_payment_terms.setdefault(idx, []) invoice_ref_based_on_payment_terms.setdefault(idx, [])
invoice_ref_based_on_payment_terms[idx].append( invoice_ref_based_on_payment_terms[idx].append(
frappe._dict( frappe._dict(
@ -1589,6 +1632,7 @@ def split_invoices_based_on_payment_terms(outstanding_invoices):
"posting_date": d.posting_date, "posting_date": d.posting_date,
"invoice_amount": flt(d.invoice_amount), "invoice_amount": flt(d.invoice_amount),
"outstanding_amount": flt(d.outstanding_amount), "outstanding_amount": flt(d.outstanding_amount),
"payment_term_outstanding": payment_term_outstanding,
"payment_amount": payment_term.payment_amount, "payment_amount": payment_term.payment_amount,
"payment_term": payment_term.payment_term, "payment_term": payment_term.payment_term,
"account": d.account, "account": d.account,
@ -2371,6 +2415,7 @@ def get_reference_as_per_payment_terms(
"due_date": doc.get("due_date"), "due_date": doc.get("due_date"),
"total_amount": grand_total, "total_amount": grand_total,
"outstanding_amount": outstanding_amount, "outstanding_amount": outstanding_amount,
"payment_term_outstanding": payment_term_outstanding,
"payment_term": payment_term.payment_term, "payment_term": payment_term.payment_term,
"allocated_amount": payment_term_outstanding, "allocated_amount": payment_term_outstanding,
} }