fix: validate DN against SRE
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index d6d51af..55a4975 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -147,6 +147,8 @@
 
 		if not self.installation_status:
 			self.installation_status = "Not Installed"
+
+		self.validate_against_sre()
 		self.reset_default_field_value("set_warehouse", "items", "warehouse")
 
 	def validate_with_previous_doc(self):
@@ -282,6 +284,78 @@
 				if item.against_sre:
 					update_delivered_qty(item.doctype, item.against_sre)
 
+	def validate_against_sre(self):
+		from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
+			get_stock_reservation_entry_for_items,
+			has_reserved_stock,
+		)
+
+		sre_details = get_stock_reservation_entry_for_items(self.items)
+
+		for item in self.items:
+			if item.against_sre:
+				sre = sre_details[item.against_sre]
+
+				# SRE `docstatus` should be `1` (submitted)
+				if sre.docstatus == 0:
+					frappe.throw(
+						_("Row #{0}: Stock Reservation Entry {1} is not submitted").format(
+							item.idx, item.against_sre
+						)
+					)
+				elif sre.docstatus == 2:
+					frappe.throw(
+						_("Row #{0}: Stock Reservation Entry {0} is cancelled").format(item.idx, item.against_sre)
+					)
+
+				# SRE `status` should not be `Delivered`
+				if sre.status == "Delivered":
+					frappe.throw(
+						_("Row #{0}: Cannot deliver more against Stock Reservation Entry {1}").format(
+							item.idx, item.against_sre
+						)
+					)
+
+				for field in (
+					"item_code",
+					"warehouse",
+					("against_sales_order", "voucher_no"),
+					("so_detail", "voucher_detail_no"),
+				):
+					item_field = sre_field = None
+
+					if isinstance(field, tuple):
+						item_field, sre_field = field[0], field[1]
+					else:
+						item_field = sre_field = field
+
+					if item.get(item_field) != sre.get(sre_field):
+						frappe.throw(
+							_("Row #{0}: {1} {2} does not match with Stock Reservation Entry {3}").format(
+								item.idx,
+								frappe.get_meta(item.doctype).get_label(item_field),
+								item.get(item_field),
+								item.against_sre,
+							)
+						)
+
+				max_delivered_qty = (sre.reserved_qty - sre.delivered_qty) / item.conversion_factor
+				if item.qty > max_delivered_qty:
+					frappe.throw(
+						_("Row #{0}: Cannot deliver more than {1} {2} against Stock Reservation Entry {3}").format(
+							item.idx, max_delivered_qty, item.uom, item.against_sre
+						)
+					)
+			elif item.against_sales_order:
+				if not item.so_detail:
+					frappe.throw(_("Row #{0}: Sales Order Item reference is required").format(item.idx))
+				elif has_reserved_stock("Sales Order", item.against_sales_order, item.so_detail):
+					frappe.throw(
+						_("Row #{0}: Cannot deliver against Sales Order {1} without Stock Reservation Entry").format(
+							item.idx, item.against_sales_order
+						)
+					)
+
 	def check_credit_limit(self):
 		from erpnext.selling.doctype.customer.customer import check_credit_limit
 
diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py
index 82eebb4..3c5b621 100644
--- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py
+++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py
@@ -131,3 +131,34 @@
 	sre_doc.delivered_qty = delivered_qty
 	sre_doc.db_update()
 	sre_doc.update_status()
+
+
+def get_stock_reservation_entry_for_items(items, sre_field="against_sre"):
+	sre_details = {}
+
+	sre_list = [item.get(sre_field) for item in items if item.get(sre_field)]
+
+	if sre_list:
+		sre = frappe.qb.DocType("Stock Reservation Entry")
+		sre_data = (
+			frappe.qb.from_(sre)
+			.select(
+				sre.name,
+				sre.status,
+				sre.docstatus,
+				sre.item_code,
+				sre.warehouse,
+				sre.voucher_type,
+				sre.voucher_no,
+				sre.voucher_detail_no,
+				sre.reserved_qty,
+				sre.delivered_qty,
+				sre.stock_uom,
+			)
+			.where(sre.name.isin(sre_list))
+			.orderby(sre.creation)
+		).run(as_dict=True)
+
+		sre_details = {d.name: d for d in sre_data}
+
+	return sre_details