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)