Merge branch 'develop' into maint_sch_link_fix
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
index 2ffae1a..9c35f4f 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
@@ -1,7 +1,6 @@
 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 # License: GNU General Public License v3. See license.txt
 
-
 import frappe
 from frappe import _, throw
 from frappe.utils import add_days, cint, cstr, date_diff, formatdate, getdate
@@ -306,13 +305,18 @@
 					return schedule.name
 
 @frappe.whitelist()
-def update_serial_nos(s_id):
-	serial_nos = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'serial_no')
+def update_serial_nos(item_code, schedule=None):
+	serial_nos = []
+	if schedule:
+		serial_nos = frappe.db.get_value('Maintenance Schedule Item', {
+			'parent': schedule,
+			'item_code': item_code
+		}, 'serial_no')
+
 	if serial_nos:
 		serial_nos = get_serial_nos(serial_nos)
-		return serial_nos
-	else:
-		return False
+
+	return serial_nos
 
 @frappe.whitelist()
 def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=None):
@@ -320,12 +324,9 @@
 
 	def update_status_and_detail(source, target, parent):
 		target.maintenance_type = "Scheduled"
-		target.maintenance_schedule = source.name
 		target.maintenance_schedule_detail = s_id
 
-	def update_sales_and_serial(source, target, parent):
-		sales_person = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'sales_person')
-		target.service_person = sales_person
+	def update_serial(source, target, parent):
 		serial_nos = get_serial_nos(target.serial_no)
 		if len(serial_nos) == 1:
 			target.serial_no = serial_nos[0]
@@ -346,7 +347,10 @@
 		"Maintenance Schedule Item": {
 			"doctype": "Maintenance Visit Purpose",
 			"condition": lambda doc: doc.item_name == item_name,
-			"postprocess": update_sales_and_serial
+			"field_map": {
+				"sales_person": "service_person"
+			},
+			"postprocess": update_serial
 		}
 	}, target_doc)
 
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
index 6f6ca61..edfc5e4 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
@@ -2,45 +2,39 @@
 // License: GNU General Public License v3. See license.txt
 
 frappe.provide("erpnext.maintenance");
-var serial_nos = [];
 frappe.ui.form.on('Maintenance Visit', {
-	refresh: function (frm) {
-		//filters for serial_no based on item_code
-		frm.set_query('serial_no', 'purposes', function (frm, cdt, cdn) {
-			let item = locals[cdt][cdn];
-			if (serial_nos) {
-				return {
-					filters: {
-						'item_code': item.item_code,
-						'name': ["in", serial_nos]
-					}
-				};
-			} else {
-				return {
-					filters: {
-						'item_code': item.item_code
-					}
-				};
-			}
-		});
-	},
 	setup: function (frm) {
 		frm.set_query('contact_person', erpnext.queries.contact_query);
 		frm.set_query('customer_address', erpnext.queries.address_query);
 		frm.set_query('customer', erpnext.queries.customer);
 	},
-	onload: function (frm, cdt, cdn) {
-		let item = locals[cdt][cdn];
+	onload: function (frm) {
+		// filters for serial no based on item code
 		if (frm.doc.maintenance_type === "Scheduled") {
-			const schedule_id = item.purposes[0].prevdoc_detail_docname || frm.doc.maintenance_schedule_detail;
+			let item_code = frm.doc.purposes[0].item_code;
 			frappe.call({
 				method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos",
 				args: {
-					s_id: schedule_id
-				},
-				callback: function (r) {
-					serial_nos = r.message;
+					schedule: frm.doc.maintenance_schedule,
+					item_code: item_code
 				}
+			}).then((r) => {
+				let serial_nos = r.message;
+				frm.set_query('serial_no', 'purposes', () => {
+					if (serial_nos.length > 0) {
+						return {
+							filters: {
+								'item_code': item_code,
+								'name': ["in", serial_nos]
+							}
+						};
+					}
+					return {
+						filters: {
+							'item_code': item_code
+						}
+					};
+				});
 			});
 		}
 		if (!frm.doc.status) {
@@ -60,7 +54,6 @@
 	contact_person: function (frm) {
 		erpnext.utils.get_contact_details(frm);
 	}
-
 })
 
 // TODO commonify this code
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 65ad79e..6bee3ac 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -313,6 +313,7 @@
 erpnext.patches.v13_0.create_pan_field_for_india #2
 erpnext.patches.v14_0.delete_hub_doctypes
 erpnext.patches.v13_0.create_ksa_vat_custom_fields
+erpnext.patches.v13_0.update_maintenance_schedule_field_in_visit
 erpnext.patches.v14_0.rename_ongoing_status_in_sla_documents
 erpnext.patches.v14_0.migrate_crm_settings
 erpnext.patches.v13_0.rename_ksa_qr_field
diff --git a/erpnext/patches/v13_0/update_maintenance_schedule_field_in_visit.py b/erpnext/patches/v13_0/update_maintenance_schedule_field_in_visit.py
new file mode 100644
index 0000000..450c00e
--- /dev/null
+++ b/erpnext/patches/v13_0/update_maintenance_schedule_field_in_visit.py
@@ -0,0 +1,22 @@
+
+import frappe
+
+
+def execute():
+	# Updates the Maintenance Schedule link to fetch serial nos
+	from frappe.query_builder.functions import Coalesce
+	mvp = frappe.qb.DocType('Maintenance Visit Purpose')
+	mv = frappe.qb.DocType('Maintenance Visit')
+
+	frappe.qb.update(
+		mv
+	).join(
+		mvp
+	).on(mvp.parent == mv.name).set(
+		mv.maintenance_schedule,
+		Coalesce(mvp.prevdoc_docname, '')
+	).where(
+		(mv.maintenance_type == "Scheduled")
+		& (mvp.prevdoc_docname.notnull())
+		& (mv.docstatus < 2)
+	).run(as_dict=1)