fix: round running allocation balance in payment reconciliation (backport #58393) (#59356)

Co-authored-by: Vishnu Priya Baskaran <145791817+ervishnucs@users.noreply.github.com>
Co-authored-by: diptanilsaha <diptanil@frappe.io>
This commit is contained in:
mergify[bot]
2026-09-23 22:25:40 +00:00
committed by GitHub
parent aea326869b
commit 3a7d756714
2 changed files with 84 additions and 2 deletions

View File

@@ -455,6 +455,13 @@ class PaymentReconciliation(Document):
default_exchange_gain_loss_account = frappe.get_cached_value(
"Company", self.company, "exchange_gain_loss_account"
)
account_currency = frappe.get_cached_value(
"Account", self.receivable_payable_account, "account_currency"
)
allocated_amount_precision = get_field_precision(
frappe.get_meta("Payment Reconciliation Allocation").get_field("allocated_amount"),
currency=account_currency,
)
entries = []
for pay in args.get("payments"):
@@ -462,11 +469,17 @@ class PaymentReconciliation(Document):
for inv in args.get("invoices"):
if pay.get("amount") >= inv.get("outstanding_amount"):
res = self.get_allocated_entry(pay, inv, inv["outstanding_amount"])
pay["amount"] = flt(pay.get("amount")) - flt(inv.get("outstanding_amount"))
pay["amount"] = flt(
flt(pay.get("amount")) - flt(inv.get("outstanding_amount")),
allocated_amount_precision,
)
inv["outstanding_amount"] = 0
else:
res = self.get_allocated_entry(pay, inv, pay["amount"])
inv["outstanding_amount"] = flt(inv.get("outstanding_amount")) - flt(pay.get("amount"))
inv["outstanding_amount"] = flt(
flt(inv.get("outstanding_amount")) - flt(pay.get("amount")),
allocated_amount_precision,
)
pay["amount"] = 0
inv["exchange_rate"] = invoice_exchange_map.get(inv.get("invoice_number"))

View File

@@ -1484,6 +1484,75 @@ class TestPaymentReconciliation(FrappeTestCase):
# Should not raise frappe.exceptions.ValidationError: Payment Entry has been modified after you pulled it. Please pull it again.
pr.reconcile()
@change_settings("System Settings", {"currency_precision": 2})
def test_allocate_entries_rounds_running_balance_to_currency_precision(self):
pr = frappe.new_doc("Payment Reconciliation")
pr.company = self.company
pr.party_type = "Customer"
pr.party = self.customer
pr.receivable_payable_account = self.debit_to
pr.set("invoices", [{"invoice_number": "INV-1"}])
pr.set("payments", [{"reference_name": "PAY-1"}])
invoices = [
{
"invoice_type": "Sales Invoice",
"invoice_number": "INV-1",
"outstanding_amount": 17592.415,
"currency": "INR",
},
]
payments = [
{
"reference_type": "Payment Entry",
"reference_name": "PAY-1",
"amount": 18230,
"currency": "INR",
}
]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
self.assertEqual(payments[0]["amount"], flt(637.585, 2))
@change_settings("System Settings", {"currency_precision": "", "use_number_format_from_currency": 1})
def test_allocate_entries_rounds_running_balance_to_account_currency_precision(self):
account_currency = frappe.get_cached_value("Account", self.debit_to, "account_currency")
original_number_format = frappe.db.get_value("Currency", account_currency, "number_format")
frappe.db.set_value("Currency", account_currency, "number_format", "#,###.###")
self.addCleanup(
frappe.db.set_value, "Currency", account_currency, "number_format", original_number_format
)
pr = frappe.new_doc("Payment Reconciliation")
pr.company = self.company
pr.party_type = "Customer"
pr.party = self.customer
pr.receivable_payable_account = self.debit_to
pr.set("invoices", [{"invoice_number": "INV-1"}])
pr.set("payments", [{"reference_name": "PAY-1"}])
invoices = [
{
"invoice_type": "Sales Invoice",
"invoice_number": "INV-1",
"outstanding_amount": 17592.415,
"currency": account_currency,
},
]
payments = [
{
"reference_type": "Payment Entry",
"reference_name": "PAY-1",
"amount": 18230,
"currency": account_currency,
}
]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
self.assertEqual(payments[0]["amount"], flt(637.585, 3))
def test_reverse_payment_against_payment_for_supplier(self):
"""
Reconcile a payment against a reverse payment, for a supplier.