fix: duplicate entry for serial / batch creation (#39188)

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 eede928..620b960 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
@@ -1004,13 +1004,17 @@
 	item = frappe.get_cached_value("Item", item_code, ["description", "item_code"], as_dict=1)
 
 	serial_nos = [d.get("serial_no") for d in serial_nos if d.get("serial_no")]
+	existing_serial_nos = frappe.get_all("Serial No", filters={"name": ("in", serial_nos)})
+
+	existing_serial_nos = [d.get("name") for d in existing_serial_nos if d.get("name")]
+	serial_nos = list(set(serial_nos) - set(existing_serial_nos))
+
+	if not serial_nos:
+		return
 
 	serial_nos_details = []
 	user = frappe.session.user
 	for serial_no in serial_nos:
-		if frappe.db.exists("Serial No", serial_no):
-			continue
-
 		serial_nos_details.append(
 			(
 				serial_no,
@@ -1046,9 +1050,16 @@
 
 def make_batch_nos(item_code, batch_nos):
 	item = frappe.get_cached_value("Item", item_code, ["description", "item_code"], as_dict=1)
-
 	batch_nos = [d.get("batch_no") for d in batch_nos if d.get("batch_no")]
 
+	existing_batches = frappe.get_all("Batch", filters={"name": ("in", batch_nos)})
+
+	existing_batches = [d.get("name") for d in existing_batches if d.get("name")]
+
+	batch_nos = list(set(batch_nos) - set(existing_batches))
+	if not batch_nos:
+		return
+
 	batch_nos_details = []
 	user = frappe.session.user
 	for batch_no in batch_nos:
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py
index 1975747..0d453fb 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py
@@ -10,6 +10,8 @@
 from erpnext.stock.doctype.item.test_item import make_item
 from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import (
 	add_serial_batch_ledgers,
+	make_batch_nos,
+	make_serial_nos,
 )
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
 
@@ -481,6 +483,38 @@
 		docstatus = frappe.db.get_value("Serial and Batch Bundle", bundle, "docstatus")
 		self.assertEqual(docstatus, 2)
 
+	def test_batch_duplicate_entry(self):
+		item_code = make_item(properties={"has_batch_no": 1}).name
+
+		batch_id = "TEST-BATTCCH-VAL-00001"
+		batch_nos = [{"batch_no": batch_id, "qty": 1}]
+
+		make_batch_nos(item_code, batch_nos)
+		self.assertTrue(frappe.db.exists("Batch", batch_id))
+
+		batch_id = "TEST-BATTCCH-VAL-00001"
+		batch_nos = [{"batch_no": batch_id, "qty": 1}]
+
+		# Shouldn't throw duplicate entry error
+		make_batch_nos(item_code, batch_nos)
+		self.assertTrue(frappe.db.exists("Batch", batch_id))
+
+	def test_serial_no_duplicate_entry(self):
+		item_code = make_item(properties={"has_serial_no": 1}).name
+
+		serial_no_id = "TEST-SNID-VAL-00001"
+		serial_nos = [{"serial_no": serial_no_id, "qty": 1}]
+
+		make_serial_nos(item_code, serial_nos)
+		self.assertTrue(frappe.db.exists("Serial No", serial_no_id))
+
+		serial_no_id = "TEST-SNID-VAL-00001"
+		serial_nos = [{"batch_no": serial_no_id, "qty": 1}]
+
+		# Shouldn't throw duplicate entry error
+		make_serial_nos(item_code, serial_nos)
+		self.assertTrue(frappe.db.exists("Serial No", serial_no_id))
+
 
 def get_batch_from_bundle(bundle):
 	from erpnext.stock.serial_batch_bundle import get_batch_nos