From ec739b213dd7b4b2f9f1bb264eaa06024b23672f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 26 Jun 2026 10:19:24 +0530 Subject: [PATCH 1/3] test: add coverage for FIFO Queue vs Qty After Transaction Comparison report Co-Authored-By: Claude Opus 4.8 (1M context) --- ...eue_vs_qty_after_transaction_comparison.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py diff --git a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py new file mode 100644 index 00000000000..27bf999c7f3 --- /dev/null +++ b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py @@ -0,0 +1,33 @@ +# 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.report.fifo_queue_vs_qty_after_transaction_comparison.fifo_queue_vs_qty_after_transaction_comparison import ( + execute, +) +from erpnext.tests.utils import ERPNextTestSuite + + +class TestFifoQueueVsQtyAfterTransactionComparison(ERPNextTestSuite): + def run_report(self, filters: dict) -> list: + return execute(frappe._dict(filters))[1] + + def test_healthy_fifo_item_no_mismatch(self): + item = make_item(properties={"is_stock_item": 1, "valuation_method": "FIFO"}).name + warehouse = "_Test Warehouse - _TC" + + make_stock_entry(item_code=item, to_warehouse=warehouse, qty=10, rate=100, posting_date="2026-06-01") + make_stock_entry(item_code=item, to_warehouse=warehouse, qty=5, rate=120, posting_date="2026-06-01") + make_stock_entry(item_code=item, from_warehouse=warehouse, qty=4, posting_date="2026-06-02") + + data = self.run_report({"company": "_Test Company", "item_code": item}) + + item_codes = [row.get("item_code") for row in data if row] + self.assertNotIn(item, item_codes) + + def test_requires_a_filter(self): + with self.assertRaises(frappe.ValidationError): + self.run_report({"company": "_Test Company"}) From 04617b40b41d1322451303d551d38721a05d5614 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 26 Jun 2026 13:26:37 +0530 Subject: [PATCH 2/3] test: reuse BootStrapTestData master data to reduce runtime Co-Authored-By: Claude Opus 4.8 (1M context) --- ...test_fifo_queue_vs_qty_after_transaction_comparison.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py index 27bf999c7f3..8f1b32f1209 100644 --- a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py +++ b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_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.report.fifo_queue_vs_qty_after_transaction_comparison.fifo_queue_vs_qty_after_transaction_comparison import ( execute, @@ -16,14 +15,15 @@ class TestFifoQueueVsQtyAfterTransactionComparison(ERPNextTestSuite): return execute(frappe._dict(filters))[1] def test_healthy_fifo_item_no_mismatch(self): - item = make_item(properties={"is_stock_item": 1, "valuation_method": "FIFO"}).name - warehouse = "_Test Warehouse - _TC" + item = "_Test Item" + warehouse = "Stores - _TC" + frappe.db.set_value("Item", item, "valuation_method", "FIFO") make_stock_entry(item_code=item, to_warehouse=warehouse, qty=10, rate=100, posting_date="2026-06-01") make_stock_entry(item_code=item, to_warehouse=warehouse, qty=5, rate=120, posting_date="2026-06-01") make_stock_entry(item_code=item, from_warehouse=warehouse, qty=4, posting_date="2026-06-02") - data = self.run_report({"company": "_Test Company", "item_code": item}) + data = self.run_report({"company": "_Test Company", "item_code": item, "warehouse": warehouse}) item_codes = [row.get("item_code") for row in data if row] self.assertNotIn(item, item_codes) From 875fc72842bca81810f2997e28c70d33522457e2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 1 Jul 2026 19:29:16 +0530 Subject: [PATCH 3/3] test: flag an SLE whose balance is out of sync with the FIFO queue --- ...eue_vs_qty_after_transaction_comparison.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py index 8f1b32f1209..f930edad2df 100644 --- a/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py +++ b/erpnext/stock/report/fifo_queue_vs_qty_after_transaction_comparison/test_fifo_queue_vs_qty_after_transaction_comparison.py @@ -28,6 +28,29 @@ class TestFifoQueueVsQtyAfterTransactionComparison(ERPNextTestSuite): item_codes = [row.get("item_code") for row in data if row] self.assertNotIn(item, item_codes) + def test_queue_out_of_sync_is_flagged(self): + item = "_Test Item 2" + warehouse = "Stores - _TC" + frappe.db.set_value("Item", item, "valuation_method", "FIFO") + + entry = make_stock_entry( + item_code=item, to_warehouse=warehouse, qty=10, rate=100, posting_date="2026-06-01" + ) + sle = frappe.db.get_value( + "Stock Ledger Entry", + {"voucher_no": entry.name, "item_code": item, "warehouse": warehouse}, + "name", + ) + + # corrupt the running balance so it no longer matches the FIFO queue (the queue holds 10, + # but the stored qty_after_transaction now claims 7) + frappe.db.set_value("Stock Ledger Entry", sle, "qty_after_transaction", 7, update_modified=False) + + data = self.run_report({"company": "_Test Company", "item_code": item, "warehouse": warehouse}) + + flagged = {row.get("name") for row in data if row} + self.assertIn(sle, flagged) + def test_requires_a_filter(self): with self.assertRaises(frappe.ValidationError): self.run_report({"company": "_Test Company"})