From 71a2d6e43dbd957f41e242a021831bb9e0bff26f Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 12:27:20 +0530 Subject: [PATCH] fix: validate reverse GL entries on current date under immutable ledger (backport #56709) (#56751) * fix: validate reverse GL entries on current date under immutable ledger (#56709) * fix: validate reverse GL entries on current date under immutable ledger When Immutable Ledger is enabled, the reverse GL entry is posted on the current date, but the closed-period checks in make_reverse_gl_entries still validate against the original (backdated) posting date. This blocks cancelling a backdated voucher, such as a suspense Journal Entry for a migrated NPA loan, with a books-closed error even though the reverse entry lands in an open period. Validate both check_freezing_date and validate_against_pcv against the current date when Immutable Ledger is enabled. When it is disabled, behaviour is unchanged. Follow-up to #55268. * test: reset frozen till date after reverse entry test The freeze date set on the company was not reset, so it leaked into the next test which posts entries in that period. Reset it in a finally block. * fix: prefer explicit posting_date under immutable ledger Prefer the posting_date argument before frappe.form_dict and getdate, at both the validation and the GL entry site, so an explicit date passed by the caller is honoured and validation still matches the posted date. (cherry picked from commit cab1b129c064bdbef8e01763f0f1201495d0d233) # Conflicts: # erpnext/accounts/general_ledger.py * fix: resolved conflicts Removed outdated check for freezing date in general ledger validation. * fix: Update check_freezing_date function call parameters * fix: accounts_frozen_till_date to acc_frozen_upto * test: acc_frozen_upto setting in test_period_closing_voucher --------- Co-authored-by: Nihantra C. Patel <141945075+Nihantra-Patel@users.noreply.github.com> --- .../test_period_closing_voucher.py | 15 +++++++++------ erpnext/accounts/general_ledger.py | 12 +++++++----- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py index e4e31a9adf4..e9bad6d7494 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py @@ -379,12 +379,15 @@ class TestPeriodClosingVoucher(unittest.TestCase): self.make_period_closing_voucher(posting_date="2021-03-31") - # Passed posting_date is after PCV end date, so cancellation should not fail. - make_reverse_gl_entries( - voucher_type="Journal Entry", - voucher_no=jv.name, - posting_date="2022-01-01", - ) + frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", "2021-12-31") + + try: + make_reverse_gl_entries( + voucher_type="Journal Entry", + voucher_no=jv.name, + ) + finally: + frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) totals_after_cancel = frappe.db.sql( """ diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 599173c99f5..38242a57eae 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -697,13 +697,15 @@ def make_reverse_gl_entries( partial_cancel=partial_cancel, ) validate_accounting_period(gl_entries) - check_freezing_date(gl_entries[0]["posting_date"], adv_adj) is_opening = any(d.get("is_opening") == "Yes" for d in gl_entries) - # For reverse entries, use the posting_date parameter if provided and valid - # Otherwise fall back to original posting_date - validation_date = posting_date if posting_date else gl_entries[0]["posting_date"] + if immutable_ledger_enabled: + validation_date = posting_date or frappe.form_dict.get("posting_date") or getdate() + else: + validation_date = posting_date if posting_date else gl_entries[0]["posting_date"] + + check_freezing_date(validation_date, adv_adj) validate_against_pcv(is_opening, validation_date, gl_entries[0]["company"]) if partial_cancel: @@ -770,7 +772,7 @@ def make_reverse_gl_entries( if immutable_ledger_enabled: new_gle["is_cancelled"] = 0 - new_gle["posting_date"] = frappe.form_dict.get("posting_date") or getdate() + new_gle["posting_date"] = posting_date or frappe.form_dict.get("posting_date") or getdate() elif posting_date: new_gle["posting_date"] = posting_date