Merge pull request #57889 from frappe/mergify/bp/version-16-hotfix/pr-57886

fix: incorrect entry detection in Stock Ledger Invariant Check (backport #57886)
This commit is contained in:
Mihir Kandoi
2026-08-08 11:14:13 +05:30
committed by GitHub
2 changed files with 42 additions and 3 deletions

View File

@@ -7,6 +7,8 @@ import frappe
from frappe import _
from frappe.utils import cint, flt, get_link_to_form, parse_json
from erpnext.stock.utils import get_valuation_method
SLE_FIELDS = (
"name",
"posting_date",
@@ -53,6 +55,9 @@ def add_invariant_check_fields(sles, filters):
balance_qty = 0.0
balance_stock_value = 0.0
company = frappe.get_cached_value("Warehouse", filters.warehouse, "company")
valuation_method = get_valuation_method(filters.item_code, company)
incorrect_idx = None
float_precision = cint(frappe.db.get_single_value("System Settings", "float_precision")) or 3
currency_precision = (
@@ -90,7 +95,7 @@ def add_invariant_check_fields(sles, filters):
)
sle.diff_value_diff = sle.stock_value_from_diff - sle.stock_value
if maintains_fifo_queue(sle):
if maintains_fifo_queue(sle, valuation_method):
add_fifo_fields(sle, sles[idx - 1] if idx else None)
if incorrect_idx is None and not is_sle_has_correct_data(sle, float_precision, currency_precision):
@@ -104,8 +109,10 @@ def add_invariant_check_fields(sles, filters):
return sles
def maintains_fifo_queue(sle):
# no queue is maintained for serialized/batchwise-valued stock
def maintains_fifo_queue(sle, valuation_method):
if valuation_method == "Moving Average":
return False
return not (
sle.serial_and_batch_bundle or sle.serial_no or (sle.batch_no and sle.use_batchwise_valuation)
)
@@ -138,6 +145,8 @@ def is_sle_has_correct_data(sle, float_precision, currency_precision):
return (
flt(sle.difference_in_qty, float_precision) == 0.0
and flt(sle.diff_value_diff, currency_precision) == 0.0
and flt(sle.fifo_qty_diff, float_precision) == 0.0
and flt(sle.fifo_value_diff, currency_precision) == 0.0
)

View File

@@ -1,6 +1,8 @@
# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import json
import frappe
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
@@ -59,6 +61,34 @@ class TestStockLedgerInvariantCheck(ERPNextTestSuite):
self.assertEqual(len(data), 2) # incorrect entry + one before it for context
self.assertEqual(data[-1].name, sle.name)
def test_show_incorrect_entries_catches_queue_mismatch(self):
item = self.make_movements()
sle = frappe.get_last_doc(
"Stock Ledger Entry", {"item_code": item, "warehouse": WAREHOUSE, "is_cancelled": 0}
)
tampered_queue = json.dumps([[sle.qty_after_transaction + 5, 100]])
frappe.db.set_value("Stock Ledger Entry", sle.name, "stock_queue", tampered_queue)
data = self.run_report(item_code=item, show_incorrect_entries=1)
self.assertEqual(len(data), 2)
self.assertEqual(data[-1].name, sle.name)
def test_moving_average_item_skips_fifo_queue_checks(self):
from erpnext.stock.doctype.item.test_item import make_item
item = make_item(properties={"valuation_method": "Moving Average"}).name
make_stock_entry(item_code=item, to_warehouse=WAREHOUSE, qty=10, rate=100)
make_stock_entry(item_code=item, from_warehouse=WAREHOUSE, qty=4)
data = self.run_report(item_code=item)
self.assertTrue(data)
for row in data:
self.assertIsNone(row.fifo_qty_diff)
self.assertIsNone(row.fifo_value_diff)
self.assertEqual(self.run_report(item_code=item, show_incorrect_entries=1), [])
def test_batch_item_skips_fifo_queue_checks(self):
from erpnext.stock.doctype.item.test_item import make_item