fix: update Maintenance Schedule status on Maintenance Visit submit
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
index 19f5722..ceb4406 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
@@ -131,12 +131,11 @@
 					).format(self.owner, "<br>" + "<br>".join(no_email_sp))
 				)
 
-			scheduled_date = frappe.db.sql(
-				"""select scheduled_date from
-				`tabMaintenance Schedule Detail` where item_code=%s and
-				parent=%s""",
-				(d.item_code, self.name),
-				as_dict=1,
+			scheduled_date = frappe.db.get_all(
+				"Maintenance Schedule Detail",
+				{"parent": self.name, "item_code": d.item_code},
+				["scheduled_date"],
+				as_list=False,
 			)
 
 			for key in scheduled_date:
@@ -450,20 +449,28 @@
 def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=None):
 	from frappe.model.mapper import get_mapped_doc
 
+	def condition(doc):
+		if s_id:
+			return doc.name == s_id
+		elif item_name:
+			return doc.item_name == item_name
+
+		return True
+
 	def update_status_and_detail(source, target, parent):
 		target.maintenance_type = "Scheduled"
-		target.maintenance_schedule_detail = s_id
 
 	def update_serial(source, target, parent):
-		if source.serial_and_batch_bundle:
-			serial_nos = frappe.get_doc(
-				"Serial and Batch Bundle", source.serial_and_batch_bundle
-			).get_serial_nos()
+		if source.item_reference:
+			if sbb := frappe.db.get_value(
+				"Maintenance Schedule Item", source.item_reference, "serial_and_batch_bundle"
+			):
+				serial_nos = frappe.get_doc("Serial and Batch Bundle", sbb).get_serial_nos()
 
-			if len(serial_nos) == 1:
-				target.serial_no = serial_nos[0]
-			else:
-				target.serial_no = ""
+				if len(serial_nos) == 1:
+					target.serial_no = serial_nos[0]
+				else:
+					target.serial_no = ""
 
 	doclist = get_mapped_doc(
 		"Maintenance Schedule",
@@ -475,10 +482,13 @@
 				"validation": {"docstatus": ["=", 1]},
 				"postprocess": update_status_and_detail,
 			},
-			"Maintenance Schedule Item": {
+			"Maintenance Schedule Detail": {
 				"doctype": "Maintenance Visit Purpose",
-				"condition": lambda doc: doc.item_name == item_name if item_name else True,
-				"field_map": {"sales_person": "service_person"},
+				"condition": condition,
+				"field_map": {
+					"sales_person": "service_person",
+					"name": "maintenance_schedule_detail",
+				},
 				"postprocess": update_serial,
 			},
 		},
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
index e7df484..d2511b8 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
@@ -56,20 +56,39 @@
 			frappe.throw(_("Add Items in the Purpose Table"), title=_("Purposes Required"))
 
 	def validate_maintenance_date(self):
-		if self.maintenance_type == "Scheduled" and self.maintenance_schedule_detail:
-			item_ref = frappe.db.get_value(
-				"Maintenance Schedule Detail", self.maintenance_schedule_detail, "item_reference"
-			)
-			if item_ref:
-				start_date, end_date = frappe.db.get_value(
-					"Maintenance Schedule Item", item_ref, ["start_date", "end_date"]
+		if self.maintenance_type == "Scheduled":
+			if self.maintenance_schedule_detail:
+				item_ref = frappe.db.get_value(
+					"Maintenance Schedule Detail", self.maintenance_schedule_detail, "item_reference"
 				)
-				if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(
-					self.mntc_date
-				) > get_datetime(end_date):
-					frappe.throw(
-						_("Date must be between {0} and {1}").format(format_date(start_date), format_date(end_date))
+				if item_ref:
+					start_date, end_date = frappe.db.get_value(
+						"Maintenance Schedule Item", item_ref, ["start_date", "end_date"]
 					)
+					if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(
+						self.mntc_date
+					) > get_datetime(end_date):
+						frappe.throw(
+							_("Date must be between {0} and {1}").format(format_date(start_date), format_date(end_date))
+						)
+			else:
+				for purpose in self.purposes:
+					if purpose.maintenance_schedule_detail:
+						item_ref = frappe.db.get_value(
+							"Maintenance Schedule Detail", purpose.maintenance_schedule_detail, "item_reference"
+						)
+						if item_ref:
+							start_date, end_date = frappe.db.get_value(
+								"Maintenance Schedule Item", item_ref, ["start_date", "end_date"]
+							)
+							if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(
+								self.mntc_date
+							) > get_datetime(end_date):
+								frappe.throw(
+									_("Date must be between {0} and {1}").format(
+										format_date(start_date), format_date(end_date)
+									)
+								)
 
 	def validate(self):
 		self.validate_serial_no()
@@ -82,6 +101,7 @@
 		if not cancel:
 			status = self.completion_status
 			actual_date = self.mntc_date
+
 		if self.maintenance_schedule_detail:
 			frappe.db.set_value(
 				"Maintenance Schedule Detail", self.maintenance_schedule_detail, "completion_status", status
@@ -89,6 +109,21 @@
 			frappe.db.set_value(
 				"Maintenance Schedule Detail", self.maintenance_schedule_detail, "actual_date", actual_date
 			)
+		else:
+			for purpose in self.purposes:
+				if purpose.maintenance_schedule_detail:
+					frappe.db.set_value(
+						"Maintenance Schedule Detail",
+						purpose.maintenance_schedule_detail,
+						"completion_status",
+						status,
+					)
+					frappe.db.set_value(
+						"Maintenance Schedule Detail",
+						purpose.maintenance_schedule_detail,
+						"actual_date",
+						actual_date,
+					)
 
 	def update_customer_issue(self, flag):
 		if not self.maintenance_schedule:
diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json
index ba05355..a5a63c4 100644
--- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json
+++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json
@@ -17,7 +17,8 @@
   "work_details",
   "work_done",
   "prevdoc_doctype",
-  "prevdoc_docname"
+  "prevdoc_docname",
+  "maintenance_schedule_detail"
  ],
  "fields": [
   {
@@ -49,6 +50,8 @@
    "options": "Serial No"
   },
   {
+   "fetch_from": "item_code.description",
+   "fetch_if_empty": 1,
    "fieldname": "description",
    "fieldtype": "Text Editor",
    "in_list_view": 1,
@@ -56,7 +59,6 @@
    "oldfieldname": "description",
    "oldfieldtype": "Small Text",
    "print_width": "300px",
-   "reqd": 1,
    "width": "300px"
   },
   {
@@ -103,12 +105,19 @@
   {
    "fieldname": "section_break_6",
    "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "maintenance_schedule_detail",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Maintenance Schedule Detail",
+   "options": "Maintenance Schedule Detail"
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-02-27 11:09:33.114458",
+ "modified": "2024-01-05 21:46:53.239830",
  "modified_by": "Administrator",
  "module": "Maintenance",
  "name": "Maintenance Visit Purpose",
diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py
index 3686941..1d4dab2 100644
--- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py
+++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py
@@ -14,9 +14,10 @@
 	if TYPE_CHECKING:
 		from frappe.types import DF
 
-		description: DF.TextEditor
+		description: DF.TextEditor | None
 		item_code: DF.Link | None
 		item_name: DF.Data | None
+		maintenance_schedule_detail: DF.Data | None
 		parent: DF.Data
 		parentfield: DF.Data
 		parenttype: DF.Data