fix: skip existing batch number during autogen (#31140)

diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index aac6cd3..559883f 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -86,20 +86,29 @@
 class Batch(Document):
 	def autoname(self):
 		"""Generate random ID for batch if not specified"""
-		if not self.batch_id:
-			create_new_batch, batch_number_series = frappe.db.get_value(
-				"Item", self.item, ["create_new_batch", "batch_number_series"]
-			)
 
-			if create_new_batch:
-				if batch_number_series:
-					self.batch_id = make_autoname(batch_number_series, doc=self)
-				elif batch_uses_naming_series():
-					self.batch_id = self.get_name_from_naming_series()
-				else:
-					self.batch_id = get_name_from_hash()
+		if self.batch_id:
+			self.name = self.batch_id
+			return
+
+		create_new_batch, batch_number_series = frappe.db.get_value(
+			"Item", self.item, ["create_new_batch", "batch_number_series"]
+		)
+
+		if not create_new_batch:
+			frappe.throw(_("Batch ID is mandatory"), frappe.MandatoryError)
+
+		while not self.batch_id:
+			if batch_number_series:
+				self.batch_id = make_autoname(batch_number_series, doc=self)
+			elif batch_uses_naming_series():
+				self.batch_id = self.get_name_from_naming_series()
 			else:
-				frappe.throw(_("Batch ID is mandatory"), frappe.MandatoryError)
+				self.batch_id = get_name_from_hash()
+
+			# User might have manually created a batch with next number
+			if frappe.db.exists("Batch", self.batch_id):
+				self.batch_id = None
 
 		self.name = self.batch_id
 
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index c76da62..3e470d4 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -11,6 +11,8 @@
 
 from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
 from erpnext.stock.doctype.batch.batch import UnableToSelectBatchError, get_batch_no, get_batch_qty
+from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
 from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
 	create_stock_reconciliation,
@@ -27,7 +29,7 @@
 		)
 
 	@classmethod
-	def make_batch_item(cls, item_name):
+	def make_batch_item(cls, item_name=None):
 		from erpnext.stock.doctype.item.test_item import make_item
 
 		if not frappe.db.exists(item_name):
@@ -245,7 +247,7 @@
 		if not use_naming_series:
 			frappe.set_value("Stock Settings", "Stock Settings", "use_naming_series", 0)
 
-	def make_new_batch(self, item_name, batch_id=None, do_not_insert=0):
+	def make_new_batch(self, item_name=None, batch_id=None, do_not_insert=0):
 		batch = frappe.new_doc("Batch")
 		item = self.make_batch_item(item_name)
 		batch.item = item.name
@@ -407,6 +409,26 @@
 
 		self.assertEqual(getdate(batch.expiry_date), getdate(expiry_date))
 
+	def test_autocreation_of_batches(self):
+		"""
+		Test if auto created Serial No excludes existing serial numbers
+		"""
+		item_code = make_item(
+			properties={
+				"has_batch_no": 1,
+				"batch_number_series": "BATCHEXISTING.###",
+				"create_new_batch": 1,
+			}
+		).name
+
+		manually_created_batch = self.make_new_batch(item_code, batch_id="BATCHEXISTING001").name
+
+		pr_1 = make_purchase_receipt(item_code=item_code, qty=1, batch_no=manually_created_batch)
+		pr_2 = make_purchase_receipt(item_code=item_code, qty=1)
+
+		self.assertNotEqual(pr_1.items[0].batch_no, pr_2.items[0].batch_no)
+		self.assertEqual("BATCHEXISTING002", pr_2.items[0].batch_no)
+
 
 def create_batch(item_code, rate, create_item_price_for_batch):
 	pi = make_purchase_invoice(