From 27f5235e67912f345265584fb7874b784eb6a368 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 2 Jul 2026 12:48:29 +0530 Subject: [PATCH] test: cover inconsistent balance detection in Incorrect Balance Qty report --- ...incorrect_balance_qty_after_transaction.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/erpnext/stock/report/incorrect_balance_qty_after_transaction/test_incorrect_balance_qty_after_transaction.py b/erpnext/stock/report/incorrect_balance_qty_after_transaction/test_incorrect_balance_qty_after_transaction.py index db95dd96ff6..cee67261b7d 100644 --- a/erpnext/stock/report/incorrect_balance_qty_after_transaction/test_incorrect_balance_qty_after_transaction.py +++ b/erpnext/stock/report/incorrect_balance_qty_after_transaction/test_incorrect_balance_qty_after_transaction.py @@ -3,6 +3,7 @@ import frappe +from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.report.incorrect_balance_qty_after_transaction.incorrect_balance_qty_after_transaction import ( execute, @@ -28,6 +29,30 @@ class TestIncorrectBalanceQtyAfterTransaction(ERPNextTestSuite): flagged = [row for row in data if row.get("item_code") == item] self.assertEqual(flagged, []) + def test_inconsistent_balance_qty_is_flagged(self): + # a unique item keeps this SLE the only ledger entry for the item/warehouse + item = make_item(properties={"is_stock_item": 1}).name + entry = make_stock_entry( + item_code=item, to_warehouse=WAREHOUSE, qty=10, rate=100, posting_date="2026-06-01" + ) + + # Corrupt the running balance so it no longer matches the cumulative actual_qty -- + # exactly the inconsistency this report exists to detect. set_value bypasses the + # ledger recompute that would otherwise keep the two in sync. + sle_name = frappe.db.get_value( + "Stock Ledger Entry", + {"voucher_no": entry.name, "item_code": item, "warehouse": WAREHOUSE}, + "name", + ) + frappe.db.set_value("Stock Ledger Entry", sle_name, "qty_after_transaction", 5) + + flagged = [row for row in self.run_report(item_code=item) if row.get("name") == sle_name] + self.assertEqual(len(flagged), 1, "The tampered stock ledger entry should be flagged") + row = flagged[0] + self.assertEqual(row["expected_balance_qty"], 10) # cumulative actual_qty + self.assertEqual(row["qty_after_transaction"], 5) # tampered balance + self.assertEqual(row["differnce"], 5) + def test_sequence_of_movements_not_flagged(self): item = "_Test Item 2" make_stock_entry(item_code=item, to_warehouse=WAREHOUSE, qty=20, rate=50, posting_date="2026-06-01")