mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-13 20:05:09 +00:00
fix(Payment Entry): split orders as per the schedules in the refrence table
(cherry picked from commit a9e52833fe)
This commit is contained in:
@@ -2376,9 +2376,7 @@ def get_outstanding_reference_documents(args, validate=False):
|
|||||||
vouchers=args.get("vouchers") or None,
|
vouchers=args.get("vouchers") or None,
|
||||||
)
|
)
|
||||||
|
|
||||||
outstanding_invoices = split_invoices_based_on_payment_terms(
|
outstanding_invoices = split_refdocs_based_on_payment_terms(outstanding_invoices, args.get("company"))
|
||||||
outstanding_invoices, args.get("company")
|
|
||||||
)
|
|
||||||
|
|
||||||
for d in outstanding_invoices:
|
for d in outstanding_invoices:
|
||||||
d["exchange_rate"] = 1
|
d["exchange_rate"] = 1
|
||||||
@@ -2416,6 +2414,8 @@ def get_outstanding_reference_documents(args, validate=False):
|
|||||||
filters=args,
|
filters=args,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
orders_to_be_billed = split_refdocs_based_on_payment_terms(orders_to_be_billed, args.get("company"))
|
||||||
|
|
||||||
data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
|
data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
|
||||||
|
|
||||||
if not data:
|
if not data:
|
||||||
@@ -2438,13 +2438,13 @@ def get_outstanding_reference_documents(args, validate=False):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def split_invoices_based_on_payment_terms(outstanding_invoices, company) -> list:
|
def split_refdocs_based_on_payment_terms(refdocs, company) -> list:
|
||||||
"""Split a list of invoices based on their payment terms."""
|
"""Split a list of invoices based on their payment terms."""
|
||||||
exc_rates = get_currency_data(outstanding_invoices, company)
|
exc_rates = get_currency_data(refdocs, company)
|
||||||
|
|
||||||
outstanding_invoices_after_split = []
|
outstanding_refdoc_after_split = []
|
||||||
for entry in outstanding_invoices:
|
for entry in refdocs:
|
||||||
if entry.voucher_type in ["Sales Invoice", "Purchase Invoice"]:
|
if entry.voucher_type in ["Sales Invoice", "Purchase Invoice", "Sales Order", "Purchase Order"]:
|
||||||
if payment_term_template := frappe.db.get_value(
|
if payment_term_template := frappe.db.get_value(
|
||||||
entry.voucher_type, entry.voucher_no, "payment_terms_template"
|
entry.voucher_type, entry.voucher_no, "payment_terms_template"
|
||||||
):
|
):
|
||||||
@@ -2459,25 +2459,25 @@ def split_invoices_based_on_payment_terms(outstanding_invoices, company) -> list
|
|||||||
),
|
),
|
||||||
alert=True,
|
alert=True,
|
||||||
)
|
)
|
||||||
outstanding_invoices_after_split += split_rows
|
outstanding_refdoc_after_split += split_rows
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# If not an invoice or no payment terms template, add as it is
|
# If not an invoice or no payment terms template, add as it is
|
||||||
outstanding_invoices_after_split.append(entry)
|
outstanding_refdoc_after_split.append(entry)
|
||||||
|
|
||||||
return outstanding_invoices_after_split
|
return outstanding_refdoc_after_split
|
||||||
|
|
||||||
|
|
||||||
def get_currency_data(outstanding_invoices: list, company: str | None = None) -> dict:
|
def get_currency_data(outstanding_refdocs: list, company: str | None = None) -> dict:
|
||||||
"""Get currency and conversion data for a list of invoices."""
|
"""Get currency and conversion data for a list of invoices."""
|
||||||
exc_rates = frappe._dict()
|
exc_rates = frappe._dict()
|
||||||
company_currency = frappe.db.get_value("Company", company, "default_currency") if company else None
|
company_currency = frappe.db.get_value("Company", company, "default_currency") if company else None
|
||||||
|
|
||||||
for doctype in ["Sales Invoice", "Purchase Invoice"]:
|
for doctype in ["Sales Invoice", "Purchase Invoice", "Sales Order", "Purchase Order"]:
|
||||||
invoices = [x.voucher_no for x in outstanding_invoices if x.voucher_type == doctype]
|
refdoc = [x.voucher_no for x in outstanding_refdocs if x.voucher_type == doctype]
|
||||||
for x in frappe.db.get_all(
|
for x in frappe.db.get_all(
|
||||||
doctype,
|
doctype,
|
||||||
filters={"name": ["in", invoices]},
|
filters={"name": ["in", refdoc]},
|
||||||
fields=["name", "currency", "conversion_rate", "party_account_currency"],
|
fields=["name", "currency", "conversion_rate", "party_account_currency"],
|
||||||
):
|
):
|
||||||
exc_rates[x.name] = frappe._dict(
|
exc_rates[x.name] = frappe._dict(
|
||||||
|
|||||||
@@ -2019,6 +2019,92 @@ class TestPaymentEntry(ERPNextTestSuite):
|
|||||||
self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, pe.doctype, pe.name)
|
self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, pe.doctype, pe.name)
|
||||||
self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, "Journal Entry", jv[0])
|
self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, "Journal Entry", jv[0])
|
||||||
|
|
||||||
|
def test_outstanding_orders_split_by_payment_terms(self):
|
||||||
|
create_payment_terms_template()
|
||||||
|
|
||||||
|
so = make_sales_order(do_not_save=1, qty=1, rate=200)
|
||||||
|
so.payment_terms_template = "Test Receivable Template"
|
||||||
|
so.save().submit()
|
||||||
|
|
||||||
|
args = {
|
||||||
|
"posting_date": nowdate(),
|
||||||
|
"company": so.company,
|
||||||
|
"party_type": "Customer",
|
||||||
|
"payment_type": "Receive",
|
||||||
|
"party": so.customer,
|
||||||
|
"party_account": "Debtors - _TC",
|
||||||
|
"get_orders_to_be_billed": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
references = get_outstanding_reference_documents(args)
|
||||||
|
|
||||||
|
self.assertEqual(len(references), 2)
|
||||||
|
self.assertEqual(references[0].voucher_no, so.name)
|
||||||
|
self.assertEqual(references[1].voucher_no, so.name)
|
||||||
|
self.assertEqual(references[0].payment_term, "Basic Amount Receivable")
|
||||||
|
self.assertEqual(references[1].payment_term, "Tax Receivable")
|
||||||
|
|
||||||
|
def test_outstanding_orders_no_split_when_allocate_disabled(self):
|
||||||
|
create_payment_terms_template()
|
||||||
|
|
||||||
|
template = frappe.get_doc("Payment Terms Template", "Test Receivable Template")
|
||||||
|
template.allocate_payment_based_on_payment_terms = 0
|
||||||
|
template.save()
|
||||||
|
|
||||||
|
so = make_sales_order(do_not_save=1, qty=1, rate=200)
|
||||||
|
so.payment_terms_template = "Test Receivable Template"
|
||||||
|
so.save().submit()
|
||||||
|
|
||||||
|
args = {
|
||||||
|
"posting_date": nowdate(),
|
||||||
|
"company": so.company,
|
||||||
|
"party_type": "Customer",
|
||||||
|
"payment_type": "Receive",
|
||||||
|
"party": so.customer,
|
||||||
|
"party_account": "Debtors - _TC",
|
||||||
|
"get_orders_to_be_billed": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
references = get_outstanding_reference_documents(args)
|
||||||
|
|
||||||
|
self.assertEqual(len(references), 1)
|
||||||
|
self.assertIsNone(references[0].payment_term)
|
||||||
|
|
||||||
|
template.allocate_payment_based_on_payment_terms = 1
|
||||||
|
template.save()
|
||||||
|
|
||||||
|
def test_outstanding_multicurrency_sales_order_split(self):
|
||||||
|
create_payment_terms_template()
|
||||||
|
|
||||||
|
so = make_sales_order(
|
||||||
|
customer="_Test Customer USD",
|
||||||
|
currency="USD",
|
||||||
|
qty=1,
|
||||||
|
rate=100,
|
||||||
|
do_not_submit=True,
|
||||||
|
)
|
||||||
|
so.payment_terms_template = "Test Receivable Template"
|
||||||
|
so.conversion_rate = 50
|
||||||
|
so.save().submit()
|
||||||
|
|
||||||
|
args = {
|
||||||
|
"posting_date": nowdate(),
|
||||||
|
"company": so.company,
|
||||||
|
"party_type": "Customer",
|
||||||
|
"payment_type": "Receive",
|
||||||
|
"party": so.customer,
|
||||||
|
"party_account": "Debtors - _TC",
|
||||||
|
"get_orders_to_be_billed": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
references = get_outstanding_reference_documents(args)
|
||||||
|
|
||||||
|
# Should split without throwing currency errors
|
||||||
|
self.assertEqual(len(references), 2)
|
||||||
|
for ref in references:
|
||||||
|
self.assertEqual(ref.voucher_no, so.name)
|
||||||
|
self.assertIsNotNone(ref.payment_term)
|
||||||
|
|
||||||
|
|
||||||
def create_payment_entry(**args):
|
def create_payment_entry(**args):
|
||||||
payment_entry = frappe.new_doc("Payment Entry")
|
payment_entry = frappe.new_doc("Payment Entry")
|
||||||
|
|||||||
Reference in New Issue
Block a user