From e2c12043aec418a4d629e955b4bfd03642fe3104 Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Sat, 7 Feb 2026 11:16:35 +0530 Subject: [PATCH 1/2] fix(stock): ignore pos reserved batches for stock levels (cherry picked from commit 277ba9cb794b1a979a9b3a59208f56679c20faf3) --- .../serial_and_batch_bundle/serial_and_batch_bundle.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 7ac65775b23..a0c0755c7ca 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 @@ -2690,7 +2690,10 @@ 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) + + pos_invoice_batches = frappe._dict() + if not kwargs.for_stock_levels: + pos_invoice_batches = get_reserved_batches_for_pos(kwargs) sre_reserved_batches = frappe._dict() if not kwargs.ignore_reserved_stock: From 59f6012c57e75781e5cf93b1c90e14565800ae98 Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Sat, 7 Feb 2026 11:18:06 +0530 Subject: [PATCH 2/2] test(stock): add test to ignore pos reserved batches for stock levels (cherry picked from commit 47ac67f7a23fdc0e2bc29409e4d49080cf2c3c32) --- erpnext/stock/doctype/batch/test_batch.py | 78 +++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py index 6154a982c98..31d6cc1f241 100644 --- a/erpnext/stock/doctype/batch/test_batch.py +++ b/erpnext/stock/doctype/batch/test_batch.py @@ -123,6 +123,80 @@ class TestBatch(IntegrationTestCase): for d in batches: self.assertEqual(d.qty, batchwise_qty[(d.batch_no, d.warehouse)]) + def test_batch_qty_on_pos_creation(self): + from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import ( + init_user_and_profile, + ) + from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice + from erpnext.accounts.doctype.pos_opening_entry.test_pos_opening_entry import create_opening_entry + from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import ( + get_auto_batch_nos, + ) + from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( + create_batch_item_with_batch, + ) + + invoice_type = frappe.db.get_single_value("POS Settings", "invoice_type") + session_user = frappe.session.user + + try: + # Set invoice type to POS Invoice + frappe.db.set_single_value("POS Settings", "invoice_type", "POS Invoice") + + # Create batch item + create_batch_item_with_batch("_Test BATCH ITEM", "TestBatch-RS 02") + + # Create stock entry + se = make_stock_entry( + target="_Test Warehouse - _TC", + item_code="_Test BATCH ITEM", + qty=30, + basic_rate=100, + ) + + se.reload() + + batch_no = get_batch_from_bundle(se.items[0].serial_and_batch_bundle) + + # Create opening entry + session_user = frappe.session.user + test_user, pos_profile = init_user_and_profile() + create_opening_entry(pos_profile, test_user.name) + + # POS Invoice 1, for the batch without bundle + pos_inv1 = create_pos_invoice(item="_Test BATCH ITEM", rate=300, qty=15, do_not_save=1) + pos_inv1.append( + "payments", + {"mode_of_payment": "Cash", "amount": 4500}, + ) + pos_inv1.items[0].batch_no = batch_no + pos_inv1.save() + pos_inv1.submit() + pos_inv1.reload() + + # Get auto batch nos after pos invoice + batches = get_auto_batch_nos( + frappe._dict( + { + "item_code": "_Test BATCH ITEM", + "warehouse": "_Test Warehouse - _TC", + "for_stock_levels": True, + "ignore_reserved_stock": True, + } + ) + ) + + # Check batch qty after pos invoice + row = _find_batch_row(batches, batch_no, "_Test Warehouse - _TC") + self.assertIsNotNone(row) + self.assertEqual(row.qty, 30) + + finally: + # Set invoice type to Sales Invoice + frappe.db.set_single_value("POS Settings", "invoice_type", invoice_type) + # Set user to session user + frappe.set_user(session_user) + def test_stock_entry_incoming(self): """Test batch creation via Stock Entry (Work Order)""" @@ -610,6 +684,10 @@ def create_price_list_for_batch(item_code, batch, rate): ).insert() +def _find_batch_row(batches, batch_no, warehouse): + return next((b for b in batches if b.batch_no == batch_no and b.warehouse == warehouse), None) + + def make_new_batch(**args): args = frappe._dict(args)