From 1f075d4bbf6804cd1eea962b03c8f785aff72b22 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 18 Jun 2026 13:32:46 +0530 Subject: [PATCH] feat: add batch-level option to allow negative stock for batch (cherry picked from commit ca07982ee03fea28b0554c02c4b51670960c3672) --- erpnext/stock/doctype/batch/batch.json | 11 ++++++++++- erpnext/stock/doctype/batch/batch.py | 1 + .../serial_and_batch_bundle.py | 17 +++++++++++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/batch/batch.json b/erpnext/stock/doctype/batch/batch.json index 765eb1ae05d..51127673b37 100644 --- a/erpnext/stock/doctype/batch/batch.json +++ b/erpnext/stock/doctype/batch/batch.json @@ -19,6 +19,7 @@ "stock_uom", "expiry_date", "use_batchwise_valuation", + "allow_negative_stock_for_batch", "disabled", "source", "column_break_9", @@ -199,6 +200,14 @@ { "fieldname": "column_break_xrll", "fieldtype": "Column Break" + }, + { + "default": "0", + "description": "If enabled, the system will allow negative stock entries for this batch, overriding the 'Allow negative stock for Batch' setting in Stock Settings. This may lead to incorrect valuation rates, so it is recommended to avoid using this option.", + "fieldname": "allow_negative_stock_for_batch", + "fieldtype": "Check", + "label": "Allow Negative Stock for Batch", + "no_copy": 1 } ], "icon": "fa fa-archive", @@ -206,7 +215,7 @@ "image_field": "image", "links": [], "max_attachments": 5, - "modified": "2026-06-16 16:01:26.556324", + "modified": "2026-06-17 16:01:26.556324", "modified_by": "Administrator", "module": "Stock", "name": "Batch", diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py index 40b1ac9d29e..24c620d59c8 100644 --- a/erpnext/stock/doctype/batch/batch.py +++ b/erpnext/stock/doctype/batch/batch.py @@ -94,6 +94,7 @@ class Batch(Document): if TYPE_CHECKING: from frappe.types import DF + allow_negative_stock_for_batch: DF.Check batch_id: DF.Data batch_qty: DF.Float description: DF.SmallText | None 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 83cc61423cf..faf926e7a14 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 @@ -1581,7 +1581,7 @@ class SerialandBatchBundle(Document): def throw_negative_batch(self, batch_no, available_qty, precision, posting_datetime=None): from erpnext.stock.stock_ledger import NegativeStockError - if frappe.db.get_single_value("Stock Settings", "allow_negative_stock_for_batch"): + if allow_negative_stock_for_batch(batch_no): return date_msg = "" @@ -1592,7 +1592,7 @@ class SerialandBatchBundle(Document): """ The Batch {0} of an item {1} has negative stock in the warehouse {2}{3}. Please add a stock quantity of {4} to proceed with this entry. - If it is not possible to make an adjustment entry, please enable 'Allow Negative Stock for Batch' in Stock Settings to proceed. + If it is not possible to make an adjustment entry, please enable 'Allow Negative Stock for Batch' in the batch {0} or in the Stock Settings to proceed. However, enabling this setting may lead to negative stock in the system. So please ensure the stock levels are adjusted as soon as possible to maintain the correct valuation rate.""" ).format( @@ -2188,6 +2188,19 @@ def combine_datetime(date, time=None): return get_combine_datetime(date, time) +def allow_negative_stock_for_batch(batch_no): + """Return whether negative stock is allowed for the given batch. + + The batch-level setting takes priority: if `allow_negative_stock_for_batch` + is enabled on the Batch, negative stock is allowed regardless of Stock Settings. + Otherwise, fall back to the `allow_negative_stock_for_batch` Stock Setting. + """ + if batch_no and frappe.db.get_value("Batch", batch_no, "allow_negative_stock_for_batch"): + return True + + return bool(frappe.db.get_single_value("Stock Settings", "allow_negative_stock_for_batch")) + + def get_batch(item_code): from erpnext.stock.doctype.batch.batch import make_batch