From b23c6e2687af087702409d3cd669519da0565044 Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Fri, 19 Dec 2025 12:11:04 +0530 Subject: [PATCH 1/2] fix(stock): ignore reserved stock while calculating batch qty --- erpnext/stock/doctype/batch/batch.py | 9 ++++++++- .../serial_and_batch_bundle/serial_and_batch_bundle.py | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py index 80171c6ddf3..10de964d19f 100644 --- a/erpnext/stock/doctype/batch/batch.py +++ b/erpnext/stock/doctype/batch/batch.py @@ -159,8 +159,13 @@ class Batch(Document): @frappe.whitelist() def recalculate_batch_qty(self): batches = get_batch_qty( - batch_no=self.name, item_code=self.item, for_stock_levels=True, consider_negative_batches=True + batch_no=self.name, + item_code=self.item, + for_stock_levels=True, + consider_negative_batches=True, + ignore_reserved_stock=True, ) + batch_qty = 0.0 if batches: for row in batches: @@ -241,6 +246,7 @@ def get_batch_qty( for_stock_levels=False, consider_negative_batches=False, do_not_check_future_batches=False, + ignore_reserved_stock=False, ): """Returns batch actual qty if warehouse is passed, or returns dict of qty by warehouse if warehouse is None @@ -269,6 +275,7 @@ def get_batch_qty( "for_stock_levels": for_stock_levels, "consider_negative_batches": consider_negative_batches, "do_not_check_future_batches": do_not_check_future_batches, + "ignore_reserved_stock": ignore_reserved_stock, } ) diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index 5c15245c5f6..e3ed3aa0e9c 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -2495,7 +2495,11 @@ def get_auto_batch_nos(kwargs): available_batches = get_available_batches(kwargs) stock_ledgers_batches = get_stock_ledgers_batches(kwargs) pos_invoice_batches = get_reserved_batches_for_pos(kwargs) - sre_reserved_batches = get_reserved_batches_for_sre(kwargs) + + sre_reserved_batches = frappe._dict() + if not kwargs.ignore_reserved_stock: + sre_reserved_batches = get_reserved_batches_for_sre(kwargs) + if kwargs.against_sales_order and only_consider_batches: kwargs.batch_no = kwargs.warehouse = None From 4d8ec5f54c0c063cc33990490947dd76fe029f94 Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Fri, 19 Dec 2025 17:25:20 +0530 Subject: [PATCH 2/2] test(stock): add test for ignore reserve stock --- erpnext/stock/doctype/batch/test_batch.py | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py index e93f85383ac..bc06e2beb39 100644 --- a/erpnext/stock/doctype/batch/test_batch.py +++ b/erpnext/stock/doctype/batch/test_batch.py @@ -324,6 +324,38 @@ class TestBatch(IntegrationTestCase): self.assertEqual(get_batch_qty("batch a", "_Test Warehouse - _TC"), 90) + def test_ignore_reserved_qty(self): + from erpnext.selling.doctype.sales_order.sales_order import create_pick_list + from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + + batch_item_name = "Reserve Batch Item" + batch_id = "Reserve Batch 1" + # Create Batch Item + self.make_batch_item(batch_item_name) + # Create Batch and Material Receipt Entry with qty 90 + self.make_new_batch_and_entry(batch_item_name, batch_id, "_Test Warehouse - _TC") + + # Enable Stock Reservation + frappe.db.set_single_value("Stock Settings", "enable_stock_reservation", 1) + + # Create Sales Order with qty 50 + sales_order = make_sales_order( + item_code=batch_item_name, warehouse="_Test Warehouse - _TC", qty=50, rate=20 + ) + + # Create Pick List for the Sales Order + pl = create_pick_list(sales_order.name) + pl.submit() + # Create Stock Reservation Entries + pl.create_stock_reservation_entries(notify=False) + + batch = frappe.get_doc("Batch", batch_id) + # Recalculate Batch Qty + batch.recalculate_batch_qty() + batch.reload() + # Case: Ignore Reserved Qty + self.assertEqual(batch.batch_qty, 90) + def test_total_batch_qty(self): self.make_batch_item("ITEM-BATCH-3") existing_batch_qty = flt(frappe.db.get_value("Batch", "B100", "batch_qty"))