feat: Quality Inspection on Job Card (#23964)

* feat: Quality Inspection on Job Card

* fix(Job Card): quality inspection filter query

* fix: sider issues
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index b051b32..4e8dd41 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -31,6 +31,16 @@
 			}
 		}
 
+		frm.set_query("quality_inspection", function() {
+			return {
+				query: "erpnext.stock.doctype.quality_inspection.quality_inspection.quality_inspection_query",
+				filters: {
+					"item_code": frm.doc.production_item,
+					"reference_name": frm.doc.name
+				}
+			};
+		});
+
 		frm.trigger("toggle_operation_number");
 
 		if (frm.doc.docstatus == 0 && (frm.doc.for_quantity > frm.doc.total_completed_qty || !frm.doc.for_quantity)
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json
index 575e719..5713f69 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.json
+++ b/erpnext/manufacturing/doctype/job_card/job_card.json
@@ -20,6 +20,7 @@
   "production_item",
   "item_name",
   "for_quantity",
+  "quality_inspection",
   "wip_warehouse",
   "column_break_12",
   "employee",
@@ -305,11 +306,19 @@
    "label": "Sequence Id",
    "print_hide": 1,
    "read_only": 1
+  },
+  {
+   "depends_on": "eval:!doc.__islocal;",
+   "fieldname": "quality_inspection",
+   "fieldtype": "Link",
+   "label": "Quality Inspection",
+   "no_copy": 1,
+   "options": "Quality Inspection"
   }
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-10-14 12:58:25.327897",
+ "modified": "2020-11-19 18:26:50.531664",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Job Card",
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.js b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
index 22f29e0..376848a 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.js
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
@@ -31,17 +31,27 @@
 
 // item code based on GRN/DN
 cur_frm.fields_dict['item_code'].get_query = function(doc, cdt, cdn) {
-	const doctype = (doc.reference_type == "Stock Entry") ?
-		"Stock Entry Detail" : doc.reference_type + " Item";
+	let doctype = doc.reference_type;
+
+	if (doc.reference_type !== "Job Card") {
+		doctype = (doc.reference_type == "Stock Entry") ?
+			"Stock Entry Detail" : doc.reference_type + " Item";
+	}
 
 	if (doc.reference_type && doc.reference_name) {
+		let filters = {
+			"from": doctype,
+			"inspection_type": doc.inspection_type
+		};
+
+		if (doc.reference_type == doctype)
+			filters["reference_name"] = doc.reference_name;
+		else
+			filters["parent"] = doc.reference_name;
+
 		return {
 			query: "erpnext.stock.doctype.quality_inspection.quality_inspection.item_query",
-			filters: {
-				"from": doctype,
-				"parent": doc.reference_name,
-				"inspection_type": doc.inspection_type
-			}
+			filters: filters
 		};
 	}
 },
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.json b/erpnext/stock/doctype/quality_inspection/quality_inspection.json
index dd95075..f6d7619 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.json
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.json
@@ -73,7 +73,7 @@
    "fieldname": "reference_type",
    "fieldtype": "Select",
    "label": "Reference Type",
-   "options": "\nPurchase Receipt\nPurchase Invoice\nDelivery Note\nSales Invoice\nStock Entry",
+   "options": "\nPurchase Receipt\nPurchase Invoice\nDelivery Note\nSales Invoice\nStock Entry\nJob Card",
    "reqd": 1
   },
   {
@@ -236,7 +236,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-10-21 13:03:11.938072",
+ "modified": "2020-11-19 17:06:05.409963",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Quality Inspection",
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index 399a63a..ae4eb9b 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -53,16 +53,28 @@
 
 	def update_qc_reference(self):
 		quality_inspection = self.name if self.docstatus == 1 else ""
-		doctype = self.reference_type + ' Item'
-		if self.reference_type == 'Stock Entry':
-			doctype = 'Stock Entry Detail'
 
-		if self.reference_type and self.reference_name:
-			frappe.db.sql("""update `tab{child_doc}` t1, `tab{parent_doc}` t2
-				set t1.quality_inspection = %s, t2.modified = %s
-				where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name"""
-				.format(parent_doc=self.reference_type, child_doc=doctype),
-				(quality_inspection, self.modified, self.reference_name, self.item_code))
+		if self.reference_type == 'Job Card':
+			if self.reference_name:
+				frappe.db.sql("""
+					UPDATE `tab{doctype}`
+					SET quality_inspection = %s, modified = %s
+					WHERE name = %s and production_item = %s
+				""".format(doctype=self.reference_type),
+					(quality_inspection, self.modified, self.reference_name, self.item_code))
+
+		else:
+			doctype = self.reference_type + ' Item'
+			if self.reference_type == 'Stock Entry':
+				doctype = 'Stock Entry Detail'
+
+			if self.reference_type and self.reference_name:
+				frappe.db.sql("""
+					UPDATE `tab{child_doc}` t1, `tab{parent_doc}` t2
+					SET t1.quality_inspection = %s, t2.modified = %s
+					WHERE t1.parent = %s and t1.item_code = %s and t1.parent = t2.name
+				""".format(parent_doc=self.reference_type, child_doc=doctype),
+					(quality_inspection, self.modified, self.reference_name, self.item_code))
 
 	def set_status_based_on_acceptance_formula(self):
 		for reading in self.readings:
@@ -95,27 +107,44 @@
 		mcond = get_match_cond(filters["from"])
 		cond, qi_condition = "", "and (quality_inspection is null or quality_inspection = '')"
 
-		if filters.get('from') in ['Purchase Invoice Item', 'Purchase Receipt Item']\
-				and filters.get("inspection_type") != "In Process":
-			cond = """and item_code in (select name from `tabItem` where
-				inspection_required_before_purchase = 1)"""
-		elif filters.get('from') in ['Sales Invoice Item', 'Delivery Note Item']\
-				and filters.get("inspection_type") != "In Process":
-			cond = """and item_code in (select name from `tabItem` where
-				inspection_required_before_delivery = 1)"""
-		elif filters.get('from') == 'Stock Entry Detail':
-			cond = """and s_warehouse is null"""
+		if filters.get("parent"):
+			if filters.get('from') in ['Purchase Invoice Item', 'Purchase Receipt Item']\
+					and filters.get("inspection_type") != "In Process":
+				cond = """and item_code in (select name from `tabItem` where
+					inspection_required_before_purchase = 1)"""
+			elif filters.get('from') in ['Sales Invoice Item', 'Delivery Note Item']\
+					and filters.get("inspection_type") != "In Process":
+				cond = """and item_code in (select name from `tabItem` where
+					inspection_required_before_delivery = 1)"""
+			elif filters.get('from') == 'Stock Entry Detail':
+				cond = """and s_warehouse is null"""
 
-		if filters.get('from') in ['Supplier Quotation Item']:
-			qi_condition = ""
+			if filters.get('from') in ['Supplier Quotation Item']:
+				qi_condition = ""
 
-		return frappe.db.sql(""" select item_code from `tab{doc}`
-			where parent=%(parent)s and docstatus < 2 and item_code like %(txt)s
-			{qi_condition} {cond} {mcond}
-			order by item_code limit {start}, {page_len}""".format(doc=filters.get('from'),
-			parent=filters.get('parent'), cond = cond, mcond = mcond, start = start,
-			page_len = page_len, qi_condition = qi_condition),
-			{'parent': filters.get('parent'), 'txt': "%%%s%%" % txt})
+			return frappe.db.sql("""
+					SELECT item_code
+					FROM `tab{doc}`
+					WHERE parent=%(parent)s and docstatus < 2 and item_code like %(txt)s
+					{qi_condition} {cond} {mcond}
+					ORDER BY item_code limit {start}, {page_len}
+				""".format(doc=filters.get('from'),
+					cond = cond, mcond = mcond, start = start,
+					page_len = page_len, qi_condition = qi_condition),
+					{'parent': filters.get('parent'), 'txt': "%%%s%%" % txt})
+
+		elif filters.get("reference_name"):
+			return frappe.db.sql("""
+					SELECT production_item
+					FROM `tab{doc}`
+					WHERE name = %(reference_name)s and docstatus < 2 and production_item like %(txt)s
+					{qi_condition} {cond} {mcond}
+					ORDER BY production_item
+					LIMIT {start}, {page_len}
+				""".format(doc=filters.get("from"),
+					cond = cond, mcond = mcond, start = start,
+					page_len = page_len, qi_condition = qi_condition),
+					{'reference_name': filters.get('reference_name'), 'txt': "%%%s%%" % txt})
 
 @frappe.whitelist()
 @frappe.validate_and_sanitize_search_inputs