From 403788324a7f823c5ec068b84585faa319d4112d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 26 Jun 2026 10:40:24 +0530 Subject: [PATCH 1/4] test: add coverage for Stock and Account Value Comparison report Co-Authored-By: Claude Opus 4.8 (1M context) --- ...test_stock_and_account_value_comparison.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py diff --git a/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py new file mode 100644 index 00000000000..ffff5411e90 --- /dev/null +++ b/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py @@ -0,0 +1,44 @@ +# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +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.doctype.warehouse.test_warehouse import create_warehouse +from erpnext.stock.report.stock_and_account_value_comparison.stock_and_account_value_comparison import ( + execute, +) +from erpnext.tests.utils import ERPNextTestSuite + +COMPANY = "_Test Company with perpetual inventory" + + +class TestStockAndAccountValueComparison(ERPNextTestSuite): + def test_balanced_warehouse_not_flagged(self): + warehouse = create_warehouse("_Test SAVC WH", company=COMPANY) + account = frappe.get_value("Warehouse", warehouse, "account") + item = make_item(properties={"is_stock_item": 1}).name + + make_stock_entry( + item_code=item, + to_warehouse=warehouse, + qty=10, + rate=100, + company=COMPANY, + posting_date="2026-06-01", + ) + + # Filtering by the isolated account restricts both the stock-ledger and GL + # scans to this fresh warehouse's account only. + rows = self.run_report(account=account) + + # The report lists only mismatches (rows where abs(difference_value) > 0.1), + # keyed per voucher. A balanced perpetual warehouse posts equal stock-ledger + # and GL values for the receipt voucher, so nothing should be flagged. + self.assertEqual(rows, []) + + def run_report(self, **extra): + filters = {"company": COMPANY, "as_on_date": "2026-12-31"} + filters.update(extra) + return execute(frappe._dict(filters))[1] From e005d7021b2d25bf4f9bb398bf9f490923ef688c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 26 Jun 2026 13:28:00 +0530 Subject: [PATCH 2/4] test: reuse BootStrapTestData master data to reduce runtime Co-Authored-By: Claude Opus 4.8 (1M context) --- .../test_stock_and_account_value_comparison.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py index ffff5411e90..314a1aa16f3 100644 --- a/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py +++ b/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py @@ -3,7 +3,6 @@ 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.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.report.stock_and_account_value_comparison.stock_and_account_value_comparison import ( @@ -18,7 +17,7 @@ class TestStockAndAccountValueComparison(ERPNextTestSuite): def test_balanced_warehouse_not_flagged(self): warehouse = create_warehouse("_Test SAVC WH", company=COMPANY) account = frappe.get_value("Warehouse", warehouse, "account") - item = make_item(properties={"is_stock_item": 1}).name + item = "_Test Item" make_stock_entry( item_code=item, From 497ca14747bf932ff897b16b23bf627df56b54bd Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 1 Jul 2026 15:55:33 +0530 Subject: [PATCH 3/4] test: detect a real stock/account value mismatch in comparison report --- ...test_stock_and_account_value_comparison.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py index 314a1aa16f3..82266f25354 100644 --- a/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py +++ b/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py @@ -37,6 +37,37 @@ class TestStockAndAccountValueComparison(ERPNextTestSuite): # and GL values for the receipt voucher, so nothing should be flagged. self.assertEqual(rows, []) + def test_stock_account_gl_mismatch_is_flagged(self): + warehouse = create_warehouse("_Test SAVC Mismatch WH", company=COMPANY) + account = frappe.get_value("Warehouse", warehouse, "account") + + receipt = make_stock_entry( + item_code="_Test Item", + to_warehouse=warehouse, + qty=10, + rate=100, + company=COMPANY, + posting_date="2026-06-01", + ) + + # Simulate corruption: the stock-account GL entry for this receipt drifts out of sync + # with the stock ledger (stock value stays 1000, but the account only shows 600). + frappe.db.set_value( + "GL Entry", + {"voucher_no": receipt.name, "account": account, "is_cancelled": 0}, + "debit_in_account_currency", + 600, + update_modified=False, + ) + + rows = self.run_report(account=account) + + row = next(r for r in rows if r["voucher_no"] == receipt.name) + self.assertEqual(row["ledger_type"], "Stock Ledger Entry") + self.assertEqual(row["stock_value"], 1000) # unchanged stock ledger value + self.assertEqual(row["account_value"], 600) # tampered GL value + self.assertEqual(row["difference_value"], 400) # 1000 - 600, above the 0.1 threshold + def run_report(self, **extra): filters = {"company": COMPANY, "as_on_date": "2026-12-31"} filters.update(extra) From 116b7bf67216c33cfca6cc30cda8bdddb6267265 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 1 Jul 2026 19:18:17 +0530 Subject: [PATCH 4/4] fix: minor fix Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- .../test_stock_and_account_value_comparison.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py b/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py index 2e6ee2afe58..7eabe37cc91 100644 --- a/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py +++ b/erpnext/stock/report/stock_and_account_value_comparison/test_stock_and_account_value_comparison.py @@ -67,7 +67,8 @@ class TestStockAndAccountValueComparison(ERPNextTestSuite): rows = self.run_report(account=account) - row = next(r for r in rows if r["voucher_no"] == receipt.name) + row = next((r for r in rows if r["voucher_no"] == receipt.name), None) + self.assertIsNotNone(row, "Tampered GL entry should cause the voucher to appear in the report") self.assertEqual(row["ledger_type"], "Stock Ledger Entry") self.assertEqual(row["stock_value"], 1000) # unchanged stock ledger value self.assertEqual(row["account_value"], 600) # tampered GL value