fix: allow to make BOM against template item (#21146)

* fix: allow to make BOM against template item

* Update queries.py

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 163ef72..c14bb66 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -179,6 +179,12 @@
 		# scan description only if items are less than 50000
 		description_cond = 'or tabItem.description LIKE %(txt)s'
 
+	extra_cond = " and tabItem.has_variants=0"
+	if (filters and isinstance(filters, dict)
+		and filters.get("doctype") == "BOM"):
+		extra_cond = ""
+		del filters["doctype"]
+
 	return frappe.db.sql("""select tabItem.name,
 		if(length(tabItem.item_name) > 40,
 			concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
@@ -188,11 +194,11 @@
 		{columns}
 		from tabItem
 		where tabItem.docstatus < 2
-			and tabItem.has_variants=0
 			and tabItem.disabled=0
 			and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
 			and ({scond} or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s)
 				{description_cond})
+			{extra_cond}
 			{fcond} {mcond}
 		order by
 			if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
@@ -203,6 +209,7 @@
 			key=searchfield,
 			columns=columns,
 			scond=searchfields,
+			extra_cond=extra_cond,
 			fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
 			mcond=get_match_cond(doctype).replace('%', '%%'),
 			description_cond = description_cond),
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 0051ad9..ebfb762 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -29,7 +29,10 @@
 
 		frm.set_query("item", function() {
 			return {
-				query: "erpnext.controllers.queries.item_query"
+				query: "erpnext.controllers.queries.item_query",
+				filters: {
+					"doctype": "BOM"
+				}
 			};
 		});
 
@@ -119,23 +122,58 @@
 				});
 			}
 		}
+
+
+		if (frm.doc.__onload && frm.doc.__onload["has_variants"]) {
+			frm.set_intro(__('This is a Template BOM and will be used to make the work order for {0} of the item {1}',
+				[
+					`<a class="variants-intro">variants</a>`,
+					`<a href="#Form/Item/${frm.doc.item}">${frm.doc.item}</a>`,
+				]), true);
+
+			frm.$wrapper.find(".variants-intro").on("click", () => {
+				frappe.set_route("List", "Item", {"variant_of": frm.doc.item});
+			});
+		}
 	},
 
 	make_work_order: function(frm) {
-		const fields = [{
+		const fields = [];
+
+		if (frm.doc.__onload && frm.doc.__onload["has_variants"]) {
+			fields.push({
+				fieldtype: 'Link',
+				label: __('Variant Item'),
+				fieldname: 'item',
+				options: "Item",
+				reqd: 1,
+				get_query: function() {
+					return {
+						query: "erpnext.controllers.queries.item_query",
+						filters: {
+							"variant_of": frm.doc.item
+						}
+					};
+				}
+			});
+		}
+
+		fields.push({
 			fieldtype: 'Float',
 			label: __('Qty To Manufacture'),
 			fieldname: 'qty',
 			reqd: 1,
 			default: 1
-		}];
+		});
 
 		frappe.prompt(fields, data => {
+			let item = data.item || frm.doc.item;
+
 			frappe.call({
 				method: "erpnext.manufacturing.doctype.work_order.work_order.make_work_order",
 				args: {
 					bom_no: frm.doc.name,
-					item: frm.doc.item,
+					item: item,
 					qty: data.qty || 0.0,
 					project: frm.doc.project
 				},
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index b3e602b..6ccd12a 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -59,6 +59,10 @@
 
 		self.name = name
 
+	def onload(self):
+		super(BOM, self).onload()
+		if self.get("item") and cint(frappe.db.get_value("Item", self.item, "has_variants")):
+			self.set_onload("has_variants", True)
 
 	def validate(self):
 		self.route = frappe.scrub(self.name).replace('_', '-')