From dcff5c3149a6acde4bb3c2a20bca5efc9415a385 Mon Sep 17 00:00:00 2001 From: pandiyan Date: Tue, 15 Sep 2026 21:43:02 +0530 Subject: [PATCH 1/2] fix: validate bank reconciliation date ranges (cherry picked from commit 970f32a342fb87c7c97b7088fbb99a02d5bfa1a1) # Conflicts: # erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py --- .../bank_reconciliation_tool.js | 20 ++++++- .../bank_reconciliation_tool.py | 54 +++++++++++++------ 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js index d0910a8e68c..e489ec22d51 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js @@ -68,6 +68,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", { frappe.msgprint(__("Please select Bank Account")); return; } + frm.events.validate_dates(frm); frappe.call({ method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers", args: { @@ -82,7 +83,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", { }); frm.add_custom_button(__("Get Unreconciled Entries"), function () { - frm.trigger("make_reconciliation_tool"); + return frm.trigger("make_reconciliation_tool"); }); frm.change_custom_button_type(__("Get Unreconciled Entries"), null, "primary"); }, @@ -101,7 +102,24 @@ frappe.ui.form.on("Bank Reconciliation Tool", { frm.trigger("get_account_opening_balance"); }, + validate_dates(frm) { + const from_date = frm.doc.filter_by_reference_date + ? frm.doc.from_reference_date + : frm.doc.bank_statement_from_date; + const to_date = frm.doc.filter_by_reference_date + ? frm.doc.to_reference_date + : frm.doc.bank_statement_to_date; + if (from_date && to_date && from_date > to_date) { + frappe.throw( + frm.doc.filter_by_reference_date + ? __("From Reference Date cannot be greater than To Reference Date") + : __("From Date cannot be greater than To Date") + ); + } + }, + make_reconciliation_tool(frm) { + frm.events.validate_dates(frm); frm.get_field("reconciliation_tool_cards").$wrapper.empty(); if (frm.doc.company && frm.doc.bank_account && frm.doc.bank_statement_to_date) { frm.trigger("get_cleared_balance").then(() => { diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index f249cf9c19d..94cf4a003e8 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -3,13 +3,14 @@ import json +from datetime import date import frappe from frappe import _ from frappe.model.document import Document from frappe.query_builder.custom import ConstantColumn from frappe.query_builder.functions import Sum -from frappe.utils import cint, create_batch, flt +from frappe.utils import cint, create_batch, flt, getdate from erpnext import get_default_cost_center from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount @@ -47,8 +48,12 @@ class BankReconciliationTool(Document): @frappe.whitelist() -def get_bank_transactions(bank_account, from_date=None, to_date=None): +def get_bank_transactions( + bank_account: str, from_date: str | date | None = None, to_date: str | date | None = None +): # returns bank transactions for a bank account + validate_date_range(from_date, to_date) + filters = [] filters.append(["bank_account", "=", bank_account]) filters.append(["docstatus", "=", 1]) @@ -372,13 +377,14 @@ def create_payment_entry_bts( @frappe.whitelist() def auto_reconcile_vouchers( - bank_account, - from_date=None, - to_date=None, - filter_by_reference_date=None, - from_reference_date=None, - to_reference_date=None, + bank_account: str, + from_date: str | date | None = None, + to_date: str | date | None = None, + filter_by_reference_date: bool | None = None, + from_reference_date: str | date | None = None, + to_reference_date: str | date | None = None, ): + validate_date_range(from_date, to_date, filter_by_reference_date, from_reference_date, to_reference_date) bank_transactions = get_bank_transactions(bank_account) if len(bank_transactions) > 10: @@ -488,15 +494,16 @@ def reconcile_vouchers(bank_transaction_name, vouchers): @frappe.whitelist() def get_linked_payments( - bank_transaction_name, - document_types=None, - from_date=None, - to_date=None, - filter_by_reference_date=None, - from_reference_date=None, - to_reference_date=None, + bank_transaction_name: str, + document_types: str | list[str] | None = None, + from_date: str | date | None = None, + to_date: str | date | None = None, + filter_by_reference_date: bool | None = None, + from_reference_date: str | date | None = None, + to_reference_date: str | date | None = None, ): # get all matching payments for a bank transaction + validate_date_range(from_date, to_date, filter_by_reference_date, from_reference_date, to_reference_date) transaction = frappe.get_doc("Bank Transaction", bank_transaction_name) bank_account = frappe.db.get_values( "Bank Account", transaction.bank_account, ["account", "company"], as_dict=True @@ -516,6 +523,23 @@ def get_linked_payments( return subtract_allocations(gl_account, matching) +def validate_date_range( + from_date, + to_date, + filter_by_reference_date=False, + from_reference_date=None, + to_reference_date=None, +): + if cint(filter_by_reference_date): + from_date, to_date = from_reference_date, to_reference_date + message = _("From Reference Date cannot be greater than To Reference Date") + else: + message = _("From Date cannot be greater than To Date") + + if from_date and to_date and getdate(from_date) > getdate(to_date): + frappe.throw(message) + + def subtract_allocations(gl_account, vouchers): "Look up & subtract any existing Bank Transaction allocations" copied = [] From 355033d40f8ef27b106d5514076bce3543dceadc Mon Sep 17 00:00:00 2001 From: pandiyan Date: Tue, 15 Sep 2026 21:43:05 +0530 Subject: [PATCH 2/2] test: cover bank reconciliation date validation (cherry picked from commit 62d0e2c82e5c3b26ac3102c087c5b68684919f9a) # Conflicts: # erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py --- .../test_bank_reconciliation_tool.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py index 3813052187a..9d42893d4cb 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py @@ -10,6 +10,7 @@ from frappe.utils import add_days, today from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import ( auto_reconcile_vouchers, get_bank_transactions, + get_linked_payments, ) from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry from erpnext.accounts.test.accounts_mixin import AccountsTestMixin @@ -98,3 +99,42 @@ class TestBankReconciliationTool(AccountsTestMixin, FrappeTestCase): # assert API output post reconciliation transactions = get_bank_transactions(self.bank_account, from_date, to_date) self.assertEqual(len(transactions), 0) + + def test_rejects_reversed_date_ranges(self): + from_date, to_date = today(), add_days(today(), -1) + with self.assertRaisesRegex(frappe.ValidationError, "From Date cannot be greater than To Date"): + get_bank_transactions(self.bank_account, from_date, to_date) + + with self.assertRaisesRegex( + frappe.ValidationError, "From Reference Date cannot be greater than To Reference Date" + ): + auto_reconcile_vouchers( + self.bank_account, + filter_by_reference_date=True, + from_reference_date=from_date, + to_reference_date=to_date, + ) + + transaction = ( + frappe.get_doc( + { + "doctype": "Bank Transaction", + "date": today(), + "deposit": 100, + "bank_account": self.bank_account, + "currency": "INR", + } + ) + .insert() + .submit() + ) + with self.assertRaisesRegex( + frappe.ValidationError, "From Reference Date cannot be greater than To Reference Date" + ): + get_linked_payments( + transaction.name, + ["payment_entry"], + filter_by_reference_date=True, + from_reference_date=from_date, + to_reference_date=to_date, + )