mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-18 17:08:42 +00:00
fix: extract stock ageing data helper in stock balance (backport #55774)
The v15 backport (#55776) of #55774 dropped the stock_balance.py changes. A separate backport left an inline version that sorts/filters the FIFO queue by itemgetter(1) *before* normalizing, so for batchwise valuation slots itemgetter(1) reads the count flag instead of the posting date. The queue is then ordered wrong and earliest_age/latest_age come out swapped. Extract get_stock_ageing_data, which normalizes before sorting/filtering so itemgetter(1) is always the posting date, and add the regression test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -100,8 +100,6 @@ class StockBalanceReport:
|
|||||||
self.filters["show_warehouse_wise_stock"] = True
|
self.filters["show_warehouse_wise_stock"] = True
|
||||||
item_wise_fifo_queue = FIFOSlots(self.filters, self.sle_entries).generate()
|
item_wise_fifo_queue = FIFOSlots(self.filters, self.sle_entries).generate()
|
||||||
|
|
||||||
_func = itemgetter(1)
|
|
||||||
|
|
||||||
del self.sle_entries
|
del self.sle_entries
|
||||||
|
|
||||||
sre_details = self.get_sre_reserved_qty_details()
|
sre_details = self.get_sre_reserved_qty_details()
|
||||||
@@ -126,16 +124,7 @@ class StockBalanceReport:
|
|||||||
|
|
||||||
stock_ageing_data = {"average_age": 0, "earliest_age": 0, "latest_age": 0}
|
stock_ageing_data = {"average_age": 0, "earliest_age": 0, "latest_age": 0}
|
||||||
if opening_fifo_queue:
|
if opening_fifo_queue:
|
||||||
fifo_queue = sorted(filter(_func, opening_fifo_queue), key=_func)
|
stock_ageing_data.update(get_stock_ageing_data(opening_fifo_queue, self.to_date))
|
||||||
fifo_queue = normalize_fifo_queue(fifo_queue)
|
|
||||||
if not fifo_queue:
|
|
||||||
continue
|
|
||||||
|
|
||||||
to_date = self.to_date
|
|
||||||
stock_ageing_data["average_age"] = get_average_age(fifo_queue, to_date)
|
|
||||||
stock_ageing_data["earliest_age"] = date_diff(to_date, fifo_queue[0][1])
|
|
||||||
stock_ageing_data["latest_age"] = date_diff(to_date, fifo_queue[-1][1])
|
|
||||||
stock_ageing_data["fifo_queue"] = fifo_queue
|
|
||||||
|
|
||||||
report_data.update(stock_ageing_data)
|
report_data.update(stock_ageing_data)
|
||||||
|
|
||||||
@@ -694,6 +683,21 @@ class StockBalanceReport:
|
|||||||
return opening_fifo_queue
|
return opening_fifo_queue
|
||||||
|
|
||||||
|
|
||||||
|
def get_stock_ageing_data(fifo_queue: list, to_date: str) -> dict:
|
||||||
|
stock_ageing_data = {"average_age": 0, "earliest_age": 0, "latest_age": 0}
|
||||||
|
fifo_queue = sorted(filter(itemgetter(1), normalize_fifo_queue(fifo_queue)), key=itemgetter(1))
|
||||||
|
|
||||||
|
if not fifo_queue:
|
||||||
|
return stock_ageing_data
|
||||||
|
|
||||||
|
stock_ageing_data["average_age"] = get_average_age(fifo_queue, to_date)
|
||||||
|
stock_ageing_data["earliest_age"] = date_diff(to_date, fifo_queue[0][1])
|
||||||
|
stock_ageing_data["latest_age"] = date_diff(to_date, fifo_queue[-1][1])
|
||||||
|
stock_ageing_data["fifo_queue"] = fifo_queue
|
||||||
|
|
||||||
|
return stock_ageing_data
|
||||||
|
|
||||||
|
|
||||||
def filter_items_with_no_transactions(
|
def filter_items_with_no_transactions(
|
||||||
iwb_map, float_precision: float, inventory_dimensions: list | None = None
|
iwb_map, float_precision: float, inventory_dimensions: list | None = None
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from frappe.utils import today
|
|||||||
|
|
||||||
from erpnext.stock.doctype.item.test_item import make_item
|
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.stock_entry.stock_entry_utils import make_stock_entry
|
||||||
from erpnext.stock.report.stock_balance.stock_balance import execute
|
from erpnext.stock.report.stock_balance.stock_balance import execute, get_stock_ageing_data
|
||||||
|
|
||||||
|
|
||||||
def stock_balance(filters):
|
def stock_balance(filters):
|
||||||
@@ -168,3 +168,19 @@ class TestStockBalance(FrappeTestCase):
|
|||||||
rows = stock_balance(self.filters.update({"show_variant_attributes": 1, "item_code": [variant.name]}))
|
rows = stock_balance(self.filters.update({"show_variant_attributes": 1, "item_code": [variant.name]}))
|
||||||
self.assertPartialDictEq(attributes, rows[0])
|
self.assertPartialDictEq(attributes, rows[0])
|
||||||
self.assertInvariants(rows)
|
self.assertInvariants(rows)
|
||||||
|
|
||||||
|
def test_stock_ageing_data_accepts_batchwise_valuation_slots(self):
|
||||||
|
fifo_queue = [
|
||||||
|
["SA-BATCH-NEWER", 1, 2.0, "2021-12-05", 20.0],
|
||||||
|
["SA-BATCH-OLDER", 1, 3.0, "2021-12-01", 30.0],
|
||||||
|
]
|
||||||
|
|
||||||
|
stock_ageing_data = get_stock_ageing_data(fifo_queue, "2021-12-10")
|
||||||
|
|
||||||
|
self.assertEqual(stock_ageing_data["average_age"], 7.4)
|
||||||
|
self.assertEqual(stock_ageing_data["earliest_age"], 9)
|
||||||
|
self.assertEqual(stock_ageing_data["latest_age"], 5)
|
||||||
|
self.assertEqual(
|
||||||
|
stock_ageing_data["fifo_queue"],
|
||||||
|
[[3.0, "2021-12-01", 30.0], [2.0, "2021-12-05", 20.0]],
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user