fix: production plan UX and validation message (#27278)

diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
index 6c60bbd..27d7c41 100644
--- a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
+++ b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
@@ -6,17 +6,17 @@
  "engine": "InnoDB",
  "field_order": [
   "item_code",
-  "item_name",
-  "material_request_type",
   "from_warehouse",
   "warehouse",
-  "column_break_4",
+  "item_name",
+  "material_request_type",
+  "actual_qty",
+  "ordered_qty",
   "required_bom_qty",
+  "column_break_4",
   "quantity",
   "uom",
   "projected_qty",
-  "actual_qty",
-  "ordered_qty",
   "reserved_qty_for_production",
   "safety_stock",
   "item_details",
@@ -28,6 +28,7 @@
  ],
  "fields": [
   {
+   "columns": 2,
    "fieldname": "item_code",
    "fieldtype": "Link",
    "in_list_view": 1,
@@ -41,6 +42,7 @@
    "label": "Item Name"
   },
   {
+   "columns": 2,
    "fieldname": "warehouse",
    "fieldtype": "Link",
    "in_list_view": 1,
@@ -50,10 +52,11 @@
    "reqd": 1
   },
   {
+   "columns": 1,
    "fieldname": "material_request_type",
    "fieldtype": "Select",
    "in_list_view": 1,
-   "label": "Material Request Type",
+   "label": "Type",
    "options": "\nPurchase\nMaterial Transfer\nMaterial Issue\nManufacture\nCustomer Provided"
   },
   {
@@ -61,10 +64,11 @@
    "fieldtype": "Column Break"
   },
   {
+   "columns": 1,
    "fieldname": "quantity",
    "fieldtype": "Float",
    "in_list_view": 1,
-   "label": "Required Quantity",
+   "label": "Plan to Request Qty",
    "no_copy": 1,
    "reqd": 1
   },
@@ -75,11 +79,12 @@
    "read_only": 1
   },
   {
+   "columns": 2,
    "default": "0",
    "fieldname": "actual_qty",
    "fieldtype": "Float",
    "in_list_view": 1,
-   "label": "Actual Qty",
+   "label": "Available Qty",
    "no_copy": 1,
    "read_only": 1
   },
@@ -157,16 +162,18 @@
    "read_only": 1
   },
   {
+   "columns": 2,
    "fieldname": "required_bom_qty",
    "fieldtype": "Float",
-   "label": "Required Qty as per BOM",
+   "in_list_view": 1,
+   "label": "Qty As Per BOM",
    "no_copy": 1,
    "read_only": 1
   }
  ],
  "istable": 1,
  "links": [],
- "modified": "2021-03-26 12:41:13.013149",
+ "modified": "2021-08-23 18:17:58.400462",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Material Request Plan Item",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js
index 847004f..7b4b7c3 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js
@@ -254,7 +254,7 @@
 
 	get_items_for_mr: function(frm) {
 		if (!frm.doc.for_warehouse) {
-			frappe.throw(__("Select warehouse for material requests"));
+			frappe.throw(__("To make material requests, 'Make Material Request for Warehouse' field is mandatory"));
 		}
 
 		if (frm.doc.ignore_existing_ordered_qty) {
@@ -265,9 +265,18 @@
 				title: title,
 				fields: [
 					{
-						"fieldtype": "Table MultiSelect", "label": __("Source Warehouses (Optional)"),
-						"fieldname": "warehouses", "options": "Production Plan Material Request Warehouse",
-						"description": __("System will pickup the materials from the selected warehouses. If not specified, system will create material request for purchase."),
+						'label': __('Target Warehouse'),
+						'fieldtype': 'Link',
+						'fieldname': 'target_warehouse',
+						'read_only': true,
+						'default': frm.doc.for_warehouse
+					},
+					{
+						'label': __('Source Warehouses (Optional)'),
+						'fieldtype': 'Table MultiSelect',
+						'fieldname': 'warehouses',
+						'options': 'Production Plan Material Request Warehouse',
+						'description': __('If source warehouse selected then system will create the material request with type Material Transfer from Source to Target warehouse. If not selected then will create the material request with type Purchase for the target warehouse.'),
 						get_query: function () {
 							return {
 								filters: {
@@ -342,7 +351,11 @@
 
 		frappe.prompt(fields, (row) => {
 			let get_template_url = 'erpnext.manufacturing.doctype.production_plan.production_plan.download_raw_materials';
-			open_url_post(frappe.request.url, { cmd: get_template_url, doc: frm.doc, warehouses: row.warehouses });
+			open_url_post(frappe.request.url, {
+				cmd: get_template_url,
+				doc: frm.doc,
+				warehouses: row.warehouses
+			});
 		}, __('Select Warehouses to get Stock for Materials Planning'), __('Get Stock'));
 	},
 
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json
index 8437895..b5ed288 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.json
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json
@@ -300,7 +300,7 @@
   {
    "fieldname": "for_warehouse",
    "fieldtype": "Link",
-   "label": "Material Request Warehouse",
+   "label": "Make Material Request for Warehouse",
    "options": "Warehouse"
   },
   {
@@ -364,7 +364,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-06-28 20:00:33.905114",
+ "modified": "2021-08-23 17:26:03.799876",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Production Plan",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 6b61c6d..2c77c9c 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -331,7 +331,7 @@
 	def get_production_items(self):
 		item_dict = {}
 		for d in self.po_items:
-			item_details= {
+			item_details = {
 				"production_item"		: d.item_code,
 				"use_multi_level_bom"   : d.include_exploded_items,
 				"sales_order"			: d.sales_order,
@@ -346,8 +346,7 @@
 				"production_plan"       : self.name,
 				"production_plan_item"  : d.name,
 				"product_bundle_item"	: d.product_bundle_item,
-				"planned_start_date"    : d.planned_start_date,
-				"make_work_order_for_sub_assembly_items": d.get("make_work_order_for_sub_assembly_items", 0)
+				"planned_start_date"    : d.planned_start_date
 			}
 
 			item_details.update({
@@ -458,6 +457,7 @@
 		warehouse = get_default_warehouse()
 		wo = frappe.new_doc("Work Order")
 		wo.update(item)
+		wo.planned_start_date = item.get('planned_start_date') or item.get('schedule_date')
 
 		if item.get("warehouse"):
 			wo.fg_warehouse = item.get("warehouse")
@@ -569,7 +569,10 @@
 		'Reserved Qty for Production', 'Safety Stock', 'Required Qty']]
 
 	doc.warehouse = None
-	for d in get_items_for_material_requests(doc, warehouses=warehouses, get_parent_warehouse_data=True):
+	frappe.flags.show_qty_in_stock_uom = 1
+	items = get_items_for_material_requests(doc, warehouses=warehouses, get_parent_warehouse_data=True)
+
+	for d in items:
 		item_list.append([d.get('item_code'), d.get('description'), d.get('stock_uom'), d.get('warehouse'),
 			d.get('required_bom_qty'), d.get('projected_qty'), d.get('actual_qty'), d.get('ordered_qty'),
 			d.get('planned_qty'), d.get('reserved_qty_for_production'), d.get('safety_stock'), d.get('quantity')])
@@ -605,9 +608,16 @@
 			and bom.name=%s and item.is_stock_item in (1, {0})
 		group by bei.item_code, bei.stock_uom""".format(0 if include_non_stock_items else 1),
 		(planned_qty, company, bom_no), as_dict=1):
-			item_details.setdefault(d.get('item_code'), d)
+		if not d.conversion_factor and d.purchase_uom:
+			d.conversion_factor = get_uom_conversion_factor(d.item_code, d.purchase_uom)
+		item_details.setdefault(d.get('item_code'), d)
+
 	return item_details
 
+def get_uom_conversion_factor(item_code, uom):
+	return frappe.db.get_value('UOM Conversion Detail',
+		{'parent': item_code, 'uom': uom}, 'conversion_factor')
+
 def get_subitems(doc, data, item_details, bom_no, company, include_non_stock_items,
 	include_subcontracted_items, parent_qty, planned_qty=1):
 	items = frappe.db.sql("""
@@ -642,6 +652,9 @@
 			if d.item_code in item_details:
 				item_details[d.item_code].qty = item_details[d.item_code].qty + d.qty
 			else:
+				if not d.conversion_factor and d.purchase_uom:
+					d.conversion_factor = get_uom_conversion_factor(d.item_code, d.purchase_uom)
+
 				item_details[d.item_code] = d
 
 		if data.get('include_exploded_items') and d.default_bom:
@@ -669,10 +682,11 @@
 		row['purchase_uom'] = row['stock_uom']
 
 	if row['purchase_uom'] != row['stock_uom']:
-		if not row['conversion_factor']:
+		if not (row['conversion_factor'] or frappe.flags.show_qty_in_stock_uom):
 			frappe.throw(_("UOM Conversion factor ({0} -> {1}) not found for item: {2}")
 				.format(row['purchase_uom'], row['stock_uom'], row.item_code))
-		required_qty = required_qty / row['conversion_factor']
+
+			required_qty = required_qty / row['conversion_factor']
 
 	if frappe.db.get_value("UOM", row['purchase_uom'], "must_be_whole_number"):
 		required_qty = ceil(required_qty)
@@ -841,10 +855,8 @@
 		elif data.get('item_code'):
 			item_master = frappe.get_doc('Item', data['item_code']).as_dict()
 			purchase_uom = item_master.purchase_uom or item_master.stock_uom
-			conversion_factor = 0
-			for d in item_master.get("uoms"):
-				if d.uom == purchase_uom:
-					conversion_factor = d.conversion_factor
+			conversion_factor = (get_uom_conversion_factor(item_master.name, purchase_uom)
+				if item_master.purchase_uom else 1.0)
 
 			item_details[item_master.name] = frappe._dict(
 				{