diff --git a/erpnext/stock/doctype/stock_closing_entry/stock_closing_entry.py b/erpnext/stock/doctype/stock_closing_entry/stock_closing_entry.py index 00a3b0204c4..1f8450c87c4 100644 --- a/erpnext/stock/doctype/stock_closing_entry/stock_closing_entry.py +++ b/erpnext/stock/doctype/stock_closing_entry/stock_closing_entry.py @@ -59,11 +59,10 @@ class StockClosingEntry(Document): .where( (table.docstatus == 1) & (table.company == self.company) - & ( - (table.from_date.between(self.from_date, self.to_date)) - | (table.to_date.between(self.from_date, self.to_date)) - | ((self.from_date >= table.from_date) & (table.from_date >= self.to_date)) - ) + # two date ranges overlap when each starts on or before the other ends; + # this also catches one range being fully contained within the other + & (table.from_date <= self.to_date) + & (table.to_date >= self.from_date) ) ) diff --git a/erpnext/stock/doctype/stock_closing_entry/test_stock_closing_entry.py b/erpnext/stock/doctype/stock_closing_entry/test_stock_closing_entry.py index 2f47551ff74..df5c22b6be5 100644 --- a/erpnext/stock/doctype/stock_closing_entry/test_stock_closing_entry.py +++ b/erpnext/stock/doctype/stock_closing_entry/test_stock_closing_entry.py @@ -84,6 +84,18 @@ class TestStockClosingEntryDuplicate(ERPNextTestSuite): overlap = self.make_closing("2026-02-01", "2026-04-30") self.assertRaises(frappe.ValidationError, overlap.insert) + def test_fully_contained_range_is_rejected(self): + # a range entirely inside an existing entry's range is still a duplicate + self.submit_closing(self.make_closing("2026-01-01", "2026-12-31")) + contained = self.make_closing("2026-03-01", "2026-03-31") + self.assertRaises(frappe.ValidationError, contained.insert) + + def test_enclosing_range_is_rejected(self): + # and so is a range that fully encloses an existing entry's range + self.submit_closing(self.make_closing("2026-03-01", "2026-03-31")) + enclosing = self.make_closing("2026-01-01", "2026-12-31") + self.assertRaises(frappe.ValidationError, enclosing.insert) + def test_non_overlapping_range_is_allowed(self): self.submit_closing(self.make_closing("2026-01-01", "2026-03-31")) later = self.make_closing("2026-04-01", "2026-06-30")