Merge pull request #59156 from frappe/mergify/bp/version-15-hotfix/pr-59081

fix(accounts): validate bank reconciliation date ranges (backport #59081)
This commit is contained in:
Khushi Rawat
2026-09-18 14:23:38 +05:30
committed by GitHub
3 changed files with 98 additions and 16 deletions

View File

@@ -68,6 +68,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
frappe.msgprint(__("Please select Bank Account")); frappe.msgprint(__("Please select Bank Account"));
return; return;
} }
frm.events.validate_dates(frm);
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers", method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers",
args: { args: {
@@ -82,7 +83,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
}); });
frm.add_custom_button(__("Get Unreconciled Entries"), function () { 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"); 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"); 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) { make_reconciliation_tool(frm) {
frm.events.validate_dates(frm);
frm.get_field("reconciliation_tool_cards").$wrapper.empty(); frm.get_field("reconciliation_tool_cards").$wrapper.empty();
if (frm.doc.company && frm.doc.bank_account && frm.doc.bank_statement_to_date) { if (frm.doc.company && frm.doc.bank_account && frm.doc.bank_statement_to_date) {
frm.trigger("get_cleared_balance").then(() => { frm.trigger("get_cleared_balance").then(() => {

View File

@@ -3,13 +3,14 @@
import json import json
from datetime import date
import frappe import frappe
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.query_builder.custom import ConstantColumn from frappe.query_builder.custom import ConstantColumn
from frappe.query_builder.functions import Sum 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 import get_default_cost_center
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount
@@ -47,8 +48,12 @@ class BankReconciliationTool(Document):
@frappe.whitelist() @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 # returns bank transactions for a bank account
validate_date_range(from_date, to_date)
filters = [] filters = []
filters.append(["bank_account", "=", bank_account]) filters.append(["bank_account", "=", bank_account])
filters.append(["docstatus", "=", 1]) filters.append(["docstatus", "=", 1])
@@ -372,13 +377,14 @@ def create_payment_entry_bts(
@frappe.whitelist() @frappe.whitelist()
def auto_reconcile_vouchers( def auto_reconcile_vouchers(
bank_account, bank_account: str,
from_date=None, from_date: str | date | None = None,
to_date=None, to_date: str | date | None = None,
filter_by_reference_date=None, filter_by_reference_date: bool | None = None,
from_reference_date=None, from_reference_date: str | date | None = None,
to_reference_date=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) bank_transactions = get_bank_transactions(bank_account)
if len(bank_transactions) > 10: if len(bank_transactions) > 10:
@@ -488,15 +494,16 @@ def reconcile_vouchers(bank_transaction_name, vouchers):
@frappe.whitelist() @frappe.whitelist()
def get_linked_payments( def get_linked_payments(
bank_transaction_name, bank_transaction_name: str,
document_types=None, document_types: str | list[str] | None = None,
from_date=None, from_date: str | date | None = None,
to_date=None, to_date: str | date | None = None,
filter_by_reference_date=None, filter_by_reference_date: bool | None = None,
from_reference_date=None, from_reference_date: str | date | None = None,
to_reference_date=None, to_reference_date: str | date | None = None,
): ):
# get all matching payments for a bank transaction # 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) transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
bank_account = frappe.db.get_values( bank_account = frappe.db.get_values(
"Bank Account", transaction.bank_account, ["account", "company"], as_dict=True "Bank Account", transaction.bank_account, ["account", "company"], as_dict=True
@@ -516,6 +523,23 @@ def get_linked_payments(
return subtract_allocations(gl_account, matching) 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): def subtract_allocations(gl_account, vouchers):
"Look up & subtract any existing Bank Transaction allocations" "Look up & subtract any existing Bank Transaction allocations"
copied = [] copied = []

View File

@@ -10,6 +10,7 @@ from frappe.utils import add_days, today
from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import ( from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import (
auto_reconcile_vouchers, auto_reconcile_vouchers,
get_bank_transactions, get_bank_transactions,
get_linked_payments,
) )
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
@@ -98,3 +99,42 @@ class TestBankReconciliationTool(AccountsTestMixin, FrappeTestCase):
# assert API output post reconciliation # assert API output post reconciliation
transactions = get_bank_transactions(self.bank_account, from_date, to_date) transactions = get_bank_transactions(self.bank_account, from_date, to_date)
self.assertEqual(len(transactions), 0) 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,
)