mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-12 14:11:46 +00:00
fix: incorrect entry detection in Stock Ledger Invariant Check (#57886)
(cherry picked from commit b3f97cd389)
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user