fix: do not make serial batch bundle for zero qty (#38949)
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 37916e2..9a3f7e5 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
@@ -85,6 +85,7 @@
# end: auto-generated types
def validate(self):
+ self.set_batch_no()
self.validate_serial_and_batch_no()
self.validate_duplicate_serial_and_batch_no()
self.validate_voucher_no()
@@ -99,6 +100,26 @@
self.set_incoming_rate()
self.calculate_qty_and_amount()
+ def set_batch_no(self):
+ if self.has_serial_no and self.has_batch_no:
+ serial_nos = [d.serial_no for d in self.entries if d.serial_no]
+ has_no_batch = any(not d.batch_no for d in self.entries)
+ if not has_no_batch:
+ return
+
+ serial_no_batch = frappe._dict(
+ frappe.get_all(
+ "Serial No",
+ filters={"name": ("in", serial_nos)},
+ fields=["name", "batch_no"],
+ as_list=True,
+ )
+ )
+
+ for row in self.entries:
+ if not row.batch_no:
+ row.batch_no = serial_no_batch.get(row.serial_no)
+
def validate_serial_nos_inventory(self):
if not (self.has_serial_no and self.type_of_transaction == "Outward"):
return
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index e8d652e..6819968 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -171,7 +171,7 @@
},
)
- if item_details.has_batch_no:
+ elif item_details.has_batch_no:
batch_nos_details = get_available_batches(
frappe._dict(
{
@@ -228,6 +228,9 @@
def set_new_serial_and_batch_bundle(self):
for item in self.items:
+ if not item.qty:
+ continue
+
if item.current_serial_and_batch_bundle and not item.serial_and_batch_bundle:
current_doc = frappe.get_doc("Serial and Batch Bundle", item.current_serial_and_batch_bundle)
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index 1ec99bf..70e9fb2 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -865,6 +865,66 @@
sr1.load_from_db()
self.assertEqual(sr1.difference_amount, 10000)
+ def test_make_stock_zero_for_serial_batch_item(self):
+ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+
+ serial_item = self.make_item(
+ properties={"is_stock_item": 1, "has_serial_no": 1, "serial_no_series": "DJJ.####"}
+ ).name
+ batch_item = self.make_item(
+ properties={
+ "is_stock_item": 1,
+ "has_batch_no": 1,
+ "batch_number_series": "BDJJ.####",
+ "create_new_batch": 1,
+ }
+ ).name
+
+ serial_batch_item = self.make_item(
+ properties={
+ "is_stock_item": 1,
+ "has_batch_no": 1,
+ "batch_number_series": "ADJJ.####",
+ "create_new_batch": 1,
+ "has_serial_no": 1,
+ "serial_no_series": "SN-ADJJ.####",
+ }
+ ).name
+
+ warehouse = "_Test Warehouse - _TC"
+
+ for item_code in [serial_item, batch_item, serial_batch_item]:
+ make_stock_entry(
+ item_code=item_code,
+ target=warehouse,
+ qty=10,
+ basic_rate=100,
+ )
+
+ _reco = create_stock_reconciliation(
+ item_code=item_code,
+ warehouse=warehouse,
+ qty=0.0,
+ )
+
+ serial_batch_bundle = frappe.get_all(
+ "Stock Ledger Entry",
+ {"item_code": item_code, "warehouse": warehouse, "is_cancelled": 0, "voucher_no": _reco.name},
+ "serial_and_batch_bundle",
+ )
+
+ self.assertEqual(len(serial_batch_bundle), 1)
+
+ _reco.cancel()
+
+ serial_batch_bundle = frappe.get_all(
+ "Stock Ledger Entry",
+ {"item_code": item_code, "warehouse": warehouse, "is_cancelled": 0, "voucher_no": _reco.name},
+ "serial_and_batch_bundle",
+ )
+
+ self.assertEqual(len(serial_batch_bundle), 0)
+
def create_batch_item_with_batch(item_name, batch_id):
batch_item_doc = create_item(item_name, is_stock_item=1)