refactor: remove `Against Stock Reservation Entry` field from DN Item
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 403477b..d492f71 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -622,42 +622,7 @@
 
 @frappe.whitelist()
 def make_delivery_note(source_name, target_doc=None, skip_item_mapping=False):
-	from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
-		get_stock_reservation_entries_for_voucher,
-		has_reserved_stock,
-	)
-
 	def set_missing_values(source, target):
-		if not target.items and has_reserved_stock("Sales Order", source_name):
-			sre_list = get_stock_reservation_entries_for_voucher("Sales Order", source_name)
-			sre_dict = {d.pop("voucher_detail_no"): d for d in sre_list}
-
-			for item in source.get("items"):
-				if item.name in sre_dict:
-					reserved_qty, delivered_qty, warehouse = (
-						sre_dict[item.name]["reserved_qty"],
-						sre_dict[item.name]["delivered_qty"],
-						sre_dict[item.name]["warehouse"],
-					)
-					qty_to_deliver = (reserved_qty - delivered_qty) / item.conversion_factor
-
-					row = frappe.new_doc("Delivery Note Item")
-					row.against_sales_order = source.name
-					row.against_sre = sre_dict[item.name]["name"]
-					row.so_detail = item.name
-					row.item_code = item.item_code
-					row.item_name = item.item_name
-					row.description = item.description
-					row.qty = qty_to_deliver
-					row.stock_uom = item.stock_uom
-					row.uom = item.uom
-					row.conversion_factor = item.conversion_factor
-
-					if not frappe.get_cached_value("Warehouse", warehouse, "is_group"):
-						row.warehouse = warehouse
-
-					target.append("items", row)
-
 		target.run_method("set_missing_values")
 		target.run_method("set_po_nos")
 		target.run_method("calculate_taxes_and_totals")
@@ -686,9 +651,6 @@
 				or item_group.get("buying_cost_center")
 			)
 
-	if has_reserved_stock("Sales Order", source_name):
-		skip_item_mapping = True
-
 	mapper = {
 		"Sales Order": {"doctype": "Delivery Note", "validation": {"docstatus": ["=", 1]}},
 		"Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "add_if_empty": True},
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 53b3576..ae56645 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -77,19 +77,6 @@
 			}
 		});
 
-		frm.set_query("against_sre", "items", (doc, cdt, cdn) => {
-			var row  = locals[cdt][cdn];
-			return {
-				filters: {
-					"docstatus": 1,
-					"status": ["not in", ["Delivered", "Cancelled"]],
-					"voucher_type": "Sales Order",
-					"voucher_no": row.against_sales_order,
-					"voucher_detail_no": row.so_detail,
-				}
-			}
-		});
-
 		frm.set_df_property('packed_items', 'cannot_add_rows', true);
 		frm.set_df_property('packed_items', 'cannot_delete_rows', true);
 	},
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index b8d2186..f45f8bd 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -148,7 +148,7 @@
 		if not self.installation_status:
 			self.installation_status = "Not Installed"
 
-		self.validate_against_sre()
+		self.validate_against_stock_reservation()
 		self.reset_default_field_value("set_warehouse", "items", "warehouse")
 
 	def validate_with_previous_doc(self):
@@ -262,8 +262,6 @@
 		self.update_prevdoc_status()
 		self.update_billing_status()
 
-		self.update_stock_reservation_entry()
-
 		# Updating stock ledger should always be called after updating prevdoc status,
 		# because updating reserved qty in bin depends upon updated delivered qty in SO
 		self.update_stock_ledger()
@@ -275,105 +273,87 @@
 		self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Repost Item Valuation")
 
 	def update_stock_reservation_entry(self):
-		if not self.is_return:
-			from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
-				update_sre_delivered_qty,
-			)
-
-			for item in self.get("items"):
-				if item.against_sre:
-					update_sre_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_entries_for_items,
-			has_reserved_stock,
-		)
-
-		sre_details = get_stock_reservation_entries_for_items(self.items)
+		if self.is_return or self._action != "submit":
+			return
 
 		for item in self.items:
-			if item.against_sre:
-				sre = sre_details[item.against_sre]
+			if not item.against_sales_order or not item.so_detail:
+				continue
 
-				# 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_list = frappe.db.get_all(
+				"Stock Reservation Entry",
+				{
+					"docstatus": 1,
+					"voucher_type": "Sales Order",
+					"voucher_no": item.against_sales_order,
+					"voucher_detail_no": item.so_detail,
+					"warehouse": item.warehouse,
+					"status": ["not in", ["Delivered", "Cancelled"]],
+				},
+				order_by="creation",
+			)
 
-				# 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
-						)
-					)
+			if not sre_list:
+				continue
 
-				if not frappe.get_cached_value("Warehouse", sre.warehouse, "is_group"):
-					if item.warehouse != sre.warehouse:
+			available_qty_to_deliver = item.stock_qty
+			for sre in sre_list:
+				if available_qty_to_deliver <= 0:
+					break
+
+				sre_doc = frappe.get_doc("Stock Reservation Entry", sre)
+				qty_to_be_deliver = min(sre_doc.reserved_qty - sre_doc.delivered_qty, available_qty_to_deliver)
+				sre_doc.delivered_qty += qty_to_be_deliver
+				sre_doc.db_update()
+				sre_doc.update_status()
+
+				available_qty_to_deliver -= qty_to_be_deliver
+
+	def validate_against_stock_reservation(self):
+		from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
+			get_sre_reserved_qty_details_for_voucher_detail_no,
+		)
+
+		if self.is_return:
+			return
+
+		for item in self.items:
+			if not item.against_sales_order or not item.so_detail:
+				continue
+
+			sre_data = get_sre_reserved_qty_details_for_voucher_detail_no(
+				"Sales Order", item.against_sales_order, item.so_detail
+			)
+
+			if not sre_data:
+				continue
+
+			is_group_warehouse = frappe.get_cached_value("Warehouse", sre_data[0], "is_group")
+
+			if not item.warehouse:
+				if not is_group_warehouse:
+					item.warehouse = sre_data[0]
+				else:
+					frappe.throw(_("Row #{0}: Warehouse is mandatory").format(item.idx, item.item_code))
+			else:
+				if not is_group_warehouse:
+					if item.warehouse != sre_data[0]:
 						frappe.throw(
-							_("Row #{0}: Warehouse {1} does not match with Stock Reservation Entry {2}").format(
-								item.idx, item.warehouse, item.against_sre
-							)
+							_("Row #{0}: Stock is reserved for Warehouse {1}").format(item.idx, sre_data[0]),
+							title="Stock Reservation Warehouse Mismatch",
 						)
 				else:
 					from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
 
-					warehouses = get_child_warehouses(sre.warehouse)
-
+					warehouses = get_child_warehouses(sre_data[0])
 					if item.warehouse not in warehouses:
 						frappe.throw(
-							_("Row #{0}: Warehouse {1} should be a child of Warehouse {2}").format(
-								item.idx, item.warehouse, sre.warehouse
-							)
+							_(
+								"Row #{0}: Stock is reserved for Group Warehouse {1}, please select its child Warehouse"
+							).format(item.idx, sre_data[0]),
+							title="Stock Reservation Group Warehouse",
 						)
 
-				for field in (
-					"item_code",
-					("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/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index faa7748..d3ed493 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -76,7 +76,6 @@
   "si_detail",
   "dn_detail",
   "pick_list_item",
-  "against_sre",
   "section_break_40",
   "batch_no",
   "serial_no",
@@ -833,22 +832,13 @@
    "fieldname": "material_request_item",
    "fieldtype": "Data",
    "label": "Material Request Item"
-  },
-  {
-   "fieldname": "against_sre",
-   "fieldtype": "Link",
-   "label": "Against Stock Reservation Entry",
-   "no_copy": 1,
-   "options": "Stock Reservation Entry",
-   "print_hide": 1,
-   "read_only": 1
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-03-26 16:53:08.283469",
+ "modified": "2023-03-30 23:27:30.943175",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Delivery Note Item",
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 c470493..c80ae57 100644
--- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py
+++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py
@@ -152,6 +152,24 @@
 	return query.run(as_dict=True)
 
 
+def get_sre_reserved_qty_details_for_voucher_detail_no(
+	voucher_type: str, voucher_no: str, voucher_detail_no: str
+) -> list:
+	sre = frappe.qb.DocType("Stock Reservation Entry")
+	return (
+		frappe.qb.from_(sre)
+		.select(sre.warehouse, (Sum(sre.reserved_qty) - Sum(sre.delivered_qty)).as_("reserved_qty"))
+		.where(
+			(sre.docstatus == 1)
+			& (sre.voucher_type == voucher_type)
+			& (sre.voucher_no == voucher_no)
+			& (sre.voucher_detail_no == voucher_detail_no)
+			& (sre.status.notin(["Delivered", "Cancelled"]))
+		)
+		.groupby(sre.warehouse)
+	).run(as_list=True)[0]
+
+
 def has_reserved_stock(voucher_type: str, voucher_no: str, voucher_detail_no: str = None) -> bool:
 	if get_stock_reservation_entries_for_voucher(
 		voucher_type, voucher_no, voucher_detail_no, fields=["name"]
@@ -161,56 +179,6 @@
 	return False
 
 
-def update_sre_delivered_qty(
-	doctype: str, sre_name: str, sre_field: str = "against_sre", qty_field: str = "stock_qty"
-) -> None:
-	table = frappe.qb.DocType(doctype)
-	delivered_qty = (
-		frappe.qb.from_(table)
-		.select(Sum(table[qty_field]))
-		.where((table.docstatus == 1) & (table[sre_field] == sre_name))
-	).run(as_list=True)[0][0] or 0.0
-
-	sre_doc = frappe.get_doc("Stock Reservation Entry", sre_name)
-	sre_doc.delivered_qty = delivered_qty
-	sre_doc.db_update()
-	sre_doc.update_status()
-
-
-def get_stock_reservation_entries_for_items(
-	items: list[dict | object], sre_field: str = "against_sre"
-) -> dict[dict]:
-	sre_details = {}
-
-	if items:
-		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
-
-
 def get_sre_reserved_qty_details(item_code: str | list, warehouse: str | list) -> dict:
 	sre_details = {}