feat: added negative inventory validation and restrict to make backdated entry for serial nos
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 85624d5..b55574f 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -38,6 +38,7 @@
 		self.set_supplier_address()
 		self.validate_asset_return()
 		self.validate_auto_repeat_subscription_dates()
+		self.create_package_for_transfer()
 
 		if self.doctype == "Purchase Invoice":
 			self.validate_purchase_receipt_if_update_stock()
@@ -69,6 +70,36 @@
 			),
 		)
 
+	def create_package_for_transfer(self) -> None:
+		"""Create serial and batch package for Sourece Warehouse in case of inter transfer."""
+
+		if self.is_internal_transfer() and (
+			self.doctype == "Purchase Receipt" or (self.doctype == "Purchase Invoice" and self.update_stock)
+		):
+			field = "delivery_note_item" if self.doctype == "Purchase Receipt" else "sales_invoice_item"
+
+			doctype = "Delivery Note Item" if self.doctype == "Purchase Receipt" else "Sales Invoice Item"
+
+			ids = [d.get(field) for d in self.get("items") if d.get(field)]
+			bundle_ids = {}
+			if ids:
+				for bundle in frappe.get_all(
+					doctype, filters={"name": ("in", ids)}, fields=["serial_and_batch_bundle", "name"]
+				):
+					bundle_ids[bundle.name] = bundle.serial_and_batch_bundle
+
+			if not bundle_ids:
+				return
+
+			for item in self.get("items"):
+				if item.get(field) and not item.serial_and_batch_bundle:
+					item.serial_and_batch_bundle = self.make_package_for_transfer(
+						bundle_ids.get(item.get(field)),
+						item.from_warehouse,
+						type_of_transaction="Outward",
+						do_not_submit=True,
+					)
+
 	def set_missing_values(self, for_validate=False):
 		super(BuyingController, self).set_missing_values(for_validate)
 
@@ -467,7 +498,11 @@
 						{
 							"actual_qty": flt(pr_qty),
 							"serial_no": cstr(d.serial_no).strip(),
-							"serial_and_batch_bundle": d.serial_and_batch_bundle,
+							"serial_and_batch_bundle": (
+								d.serial_and_batch_bundle
+								if not self.is_internal_transfer()
+								else self.get_package_for_target_warehouse(d)
+							),
 						},
 					)
 
@@ -494,7 +529,6 @@
 								"recalculate_rate": 1
 								if (self.is_subcontracted and (d.bom or d.fg_item)) or d.from_warehouse
 								else 0,
-								"serial_and_batch_bundle": d.serial_and_batch_bundle,
 							}
 						)
 					sl_entries.append(sle)
@@ -531,6 +565,15 @@
 			via_landed_cost_voucher=via_landed_cost_voucher,
 		)
 
+	def get_package_for_target_warehouse(self, item) -> str:
+		if not item.serial_and_batch_bundle:
+			return ""
+
+		return self.make_package_for_transfer(
+			item.serial_and_batch_bundle,
+			item.warehouse,
+		)
+
 	def update_ordered_and_reserved_qty(self):
 		po_map = {}
 		for d in self.get("items"):
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 15c84a9..1dd7209 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -531,6 +531,11 @@
 				if item_row.warehouse:
 					sle.dependant_sle_voucher_detail_no = item_row.name
 
+			if item_row.serial_and_batch_bundle:
+				sle["serial_and_batch_bundle"] = self.make_package_for_transfer(
+					item_row.serial_and_batch_bundle, item_row.target_warehouse
+				)
+
 		return sle
 
 	def set_po_nos(self, for_validate=False):
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 2e705ea..2048a42 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -372,6 +372,44 @@
 
 				row.db_set("serial_and_batch_bundle", None)
 
+	def make_package_for_transfer(
+		self, serial_and_batch_bundle, warehouse, type_of_transaction=None, do_not_submit=None
+	):
+		bundle_doc = frappe.get_doc("Serial and Batch Bundle", serial_and_batch_bundle)
+
+		if not type_of_transaction:
+			type_of_transaction = "Inward"
+
+		bundle_doc = frappe.copy_doc(bundle_doc)
+		bundle_doc.warehouse = warehouse
+		bundle_doc.type_of_transaction = type_of_transaction
+		bundle_doc.voucher_type = self.doctype
+		bundle_doc.voucher_no = self.name
+		bundle_doc.is_cancelled = 0
+
+		for row in bundle_doc.ledgers:
+			row.is_outward = 0
+			row.qty = abs(row.qty)
+			row.stock_value_difference = abs(row.stock_value_difference)
+			if type_of_transaction == "Outward":
+				row.qty *= -1
+				row.stock_value_difference *= row.stock_value_difference
+				row.is_outward = 1
+
+			row.warehouse = warehouse
+
+		bundle_doc.set_total_qty()
+		bundle_doc.set_avg_rate()
+		bundle_doc.flags.ignore_permissions = True
+
+		if not do_not_submit:
+			bundle_doc.submit()
+		else:
+			bundle_doc.save(ignore_permissions=True)
+
+		print(bundle_doc.name)
+		return bundle_doc.name
+
 	def get_sl_entries(self, d, args):
 		sl_dict = frappe._dict(
 			{