mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-17 00:18:39 +00:00
fix: preserve stock ageing on non-serial reconciliation
This commit is contained in:
@@ -358,7 +358,7 @@ class FIFOSlots:
|
|||||||
if row.voucher_type != "Stock Reconciliation":
|
if row.voucher_type != "Stock Reconciliation":
|
||||||
return
|
return
|
||||||
|
|
||||||
if not row.batch_no or row.serial_no or row.serial_and_batch_bundle:
|
if row.has_serial_no and (not row.batch_no or row.serial_no or row.serial_and_batch_bundle):
|
||||||
if row.voucher_detail_no in self.stock_reco_voucher_wise_count:
|
if row.voucher_detail_no in self.stock_reco_voucher_wise_count:
|
||||||
# Legacy reconciliation with a single SLE has qty_after_transaction and
|
# Legacy reconciliation with a single SLE has qty_after_transaction and
|
||||||
# stock_value_difference without an outward entry, so reset the queue first.
|
# stock_value_difference without an outward entry, so reset the queue first.
|
||||||
@@ -1083,6 +1083,7 @@ class FIFOSlots:
|
|||||||
(doctype.voucher_type == "Stock Reconciliation")
|
(doctype.voucher_type == "Stock Reconciliation")
|
||||||
& (doctype.docstatus < 2)
|
& (doctype.docstatus < 2)
|
||||||
& (doctype.is_cancelled == 0)
|
& (doctype.is_cancelled == 0)
|
||||||
|
& (item.has_serial_no == 1)
|
||||||
)
|
)
|
||||||
.groupby(doctype.voucher_detail_no)
|
.groupby(doctype.voucher_detail_no)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -195,6 +195,67 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
self.assertEqual(queue[0][0], 20.0)
|
self.assertEqual(queue[0][0], 20.0)
|
||||||
self.assertEqual(queue[1][0], 20.0)
|
self.assertEqual(queue[1][0], 20.0)
|
||||||
|
|
||||||
|
def test_non_serial_stock_reco_decrease_preserves_ageing(self):
|
||||||
|
"""
|
||||||
|
Non-serial stock reconciliation should adjust FIFO by the balance delta.
|
||||||
|
Decreasing stock consumes old slots; increasing stock adds only the new qty.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def make_sle(
|
||||||
|
posting_date,
|
||||||
|
voucher_type,
|
||||||
|
voucher_no,
|
||||||
|
actual_qty,
|
||||||
|
qty_after,
|
||||||
|
voucher_detail_no=None,
|
||||||
|
stock_value_difference=None,
|
||||||
|
):
|
||||||
|
stock_value_difference = actual_qty if stock_value_difference is None else stock_value_difference
|
||||||
|
|
||||||
|
return frappe._dict(
|
||||||
|
name="Flask Item",
|
||||||
|
item_name="Flask Item",
|
||||||
|
description="Flask Item",
|
||||||
|
item_group=None,
|
||||||
|
brand=None,
|
||||||
|
stock_uom="Nos",
|
||||||
|
actual_qty=actual_qty,
|
||||||
|
qty_after_transaction=qty_after,
|
||||||
|
stock_value_difference=stock_value_difference,
|
||||||
|
valuation_rate=1,
|
||||||
|
warehouse="WH 1",
|
||||||
|
posting_date=posting_date,
|
||||||
|
voucher_type=voucher_type,
|
||||||
|
voucher_no=voucher_no,
|
||||||
|
voucher_detail_no=voucher_detail_no,
|
||||||
|
has_serial_no=False,
|
||||||
|
has_batch_no=False,
|
||||||
|
serial_no=None,
|
||||||
|
batch_no=None,
|
||||||
|
serial_and_batch_bundle=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
filters = frappe._dict(company="_Test Company", to_date="2026-02-15", ranges=["30", "60", "90"])
|
||||||
|
sle = [
|
||||||
|
make_sle("2025-11-30", "Stock Entry", "001", 100, 100),
|
||||||
|
make_sle("2025-12-31", "Stock Reconciliation", "002", 0, 60, "SRI-DECREASE", -40),
|
||||||
|
make_sle("2026-01-31", "Stock Reconciliation", "003", 0, 90, "SRI-INCREASE", 30),
|
||||||
|
]
|
||||||
|
|
||||||
|
fifo_slots = FIFOSlots(filters, sle)
|
||||||
|
|
||||||
|
def prepare_stock_reco_voucher_wise_count():
|
||||||
|
fifo_slots.stock_reco_voucher_wise_count = frappe._dict({"SRI-DECREASE": 100, "SRI-INCREASE": 60})
|
||||||
|
|
||||||
|
fifo_slots.prepare_stock_reco_voucher_wise_count = prepare_stock_reco_voucher_wise_count
|
||||||
|
|
||||||
|
slots = fifo_slots.generate()
|
||||||
|
queue = slots["Flask Item"]["fifo_queue"]
|
||||||
|
report_data = format_report_data(filters, slots, filters.to_date)
|
||||||
|
|
||||||
|
self.assertEqual(queue, [[60.0, "2025-11-30", 60.0], [30.0, "2026-01-31", 30.0]])
|
||||||
|
self.assertEqual(report_data[0][7:15], [30.0, 30.0, 0.0, 0.0, 60.0, 60.0, 0.0, 0.0])
|
||||||
|
|
||||||
def test_sequential_stock_reco_same_warehouse(self):
|
def test_sequential_stock_reco_same_warehouse(self):
|
||||||
"""
|
"""
|
||||||
Test back to back stock recos (same warehouse).
|
Test back to back stock recos (same warehouse).
|
||||||
|
|||||||
Reference in New Issue
Block a user