[Enhance] Quality Inspection Template (#12988)

* [Enhance] Quality Inspection Template

* Test case and patch

* Update make_quality_inspection_template.py
diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py
index c5a372b..e3b8d82 100644
--- a/erpnext/config/stock.py
+++ b/erpnext/config/stock.py
@@ -165,6 +165,10 @@
 				},
 				{
 					"type": "doctype",
+					"name": "Quality Inspection Template",
+				},
+				{
+					"type": "doctype",
 					"name": "Landed Cost Voucher",
 				}
 			]
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 605881c..b40b986 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -320,14 +320,20 @@
 		elif self.doctype in ["Delivery Note", "Sales Invoice"]:
 			inspection_required_fieldname = "inspection_required_before_delivery"
 
-		if not inspection_required_fieldname or \
-			(self.doctype in ["Sales Invoice", "Purchase Invoice"] and not self.update_stock):
+		if ((not inspection_required_fieldname and self.doctype != "Stock Entry") or
+			(self.doctype == "Stock Entry" and not self.inspection_required) or
+			(self.doctype in ["Sales Invoice", "Purchase Invoice"] and not self.update_stock)):
 				return
 
 		for d in self.get('items'):
-			if (frappe.db.get_value("Item", d.item_code, inspection_required_fieldname)
-				and not d.quality_inspection):
+			raise_exception = False
+			if (inspection_required_fieldname and not d.quality_inspection and
+				frappe.db.get_value("Item", d.item_code, inspection_required_fieldname)):
+				raise_exception = True
+			elif self.doctype == "Stock Entry" and not d.quality_inspection and d.t_warehouse:
+				raise_exception = True
 
+			if raise_exception:
 				frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
 				if self.docstatus==1:
 					raise frappe.ValidationError
diff --git a/erpnext/controllers/tests/test_item_variant.py b/erpnext/controllers/tests/test_item_variant.py
index dfd9f9d..d4b5dd2 100644
--- a/erpnext/controllers/tests/test_item_variant.py
+++ b/erpnext/controllers/tests/test_item_variant.py
@@ -9,15 +9,22 @@
 
 from six import string_types
 
+class TestItemVariant(unittest.TestCase):
+	def test_tables_in_template_copied_to_variant(self):
+		fields = [{'field_name': 'quality_inspection_template'}]
+		set_item_variant_settings(fields)
+		variant = make_item_variant()
+		self.assertEqual(variant.get("quality_inspection_template"), "_Test QC Template")
+
 def create_variant_with_tables(item, args):
 	if isinstance(args, string_types):
 		args = json.loads(args)
 
+	qc_name = make_quality_inspection_template()
 	template = frappe.get_doc("Item", item)
-	template.quality_parameters.append({
-		"specification": "Moisture",
-		"value": "< 5%",
-	})
+	template.quality_inspection_template = qc_name
+	template.save()
+
 	variant = frappe.new_doc("Item")
 	variant.variant_based_on = 'Item Attribute'
 	variant_attributes = []
@@ -34,7 +41,6 @@
 
 	return variant
 
-
 def make_item_variant():
 	frappe.delete_doc_if_exists("Item", "_Test Variant Item-S", force=1)
 	variant = create_variant_with_tables("_Test Variant Item", '{"Test Size": "Small"}')
@@ -43,10 +49,17 @@
 	variant.save()
 	return variant
 
+def make_quality_inspection_template():
+	qc_template = "_Test QC Template"
+	if frappe.db.exists("Quality Inspection Template", qc_template):
+		return qc_template
 
-class TestItemVariant(unittest.TestCase):
-	def test_tables_in_template_copied_to_variant(self):
-		fields = [{'field_name': 'quality_parameters'}]
-		set_item_variant_settings(fields)
-		variant = make_item_variant()
-		self.assertNotEqual(variant.get("quality_parameters"), [])
+	qc = frappe.new_doc("Quality Inspection Template")
+	qc.quality_inspection_template_name = qc_template
+	qc.append('item_quality_inspection_parameter', {
+		"specification": "Moisture",
+		"value": "< 5%",
+	})
+
+	qc.insert()
+	return qc.name
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index 85a3f7e..30b9683 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -114,6 +114,68 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "fieldname": "inspection_required", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Inspection Required", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "inspection_required", 
+   "fieldname": "quality_inspection_template", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Quality Inspection Template", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Quality Inspection Template", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "cb0", 
    "fieldtype": "Column Break", 
    "hidden": 0, 
@@ -1671,7 +1733,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-10-23 14:56:21.991160", 
+ "modified": "2018-02-16 13:43:55.485813", 
  "modified_by": "Administrator", 
  "module": "Manufacturing", 
  "name": "BOM", 
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index 439659a..c41260f 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -586,6 +586,9 @@
 	stock_entry.bom_no = production_order.bom_no
 	stock_entry.use_multi_level_bom = production_order.use_multi_level_bom
 	stock_entry.fg_completed_qty = qty or (flt(production_order.qty) - flt(production_order.produced_qty))
+	if production_order.bom_no:
+		stock_entry.inspection_required = frappe.db.get_value('BOM',
+			production_order.bom_no, 'inspection_required')
 
 	if purpose=="Material Transfer for Manufacture":
 		stock_entry.to_warehouse = wip_warehouse
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 65c391e..b365e96 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -502,4 +502,5 @@
 erpnext.patches.v10_0.rename_offer_letter_to_job_offer
 execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
 erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group
+erpnext.patches.v11_0.make_quality_inspection_template
 erpnext.patches.v10_0.update_territory_and_customer_group
diff --git a/erpnext/patches/v11_0/__init__.py b/erpnext/patches/v11_0/__init__.py
new file mode 100644
index 0000000..baffc48
--- /dev/null
+++ b/erpnext/patches/v11_0/__init__.py
@@ -0,0 +1 @@
+from __future__ import unicode_literals
diff --git a/erpnext/patches/v11_0/make_quality_inspection_template.py b/erpnext/patches/v11_0/make_quality_inspection_template.py
new file mode 100644
index 0000000..67755e8
--- /dev/null
+++ b/erpnext/patches/v11_0/make_quality_inspection_template.py
@@ -0,0 +1,25 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	frappe.reload_doc('stock', 'doctype', 'item')
+	frappe.reload_doc('stock', 'doctype', 'quality_inspection_template')
+
+	for data in frappe.get_all('Item Quality Inspection Parameter',
+		fields = ["distinct parent"], filters = {'parenttype': 'Item'}):
+		qc_doc = frappe.new_doc("Quality Inspection Template")
+		qc_doc.quality_inspection_template_name = 'QIT/%s' % data.parent
+		qc_doc.flags.ignore_mandatory = True
+		qc_doc.save(ignore_permissions=True)
+
+		frappe.db.set_value('Item', data.parent, "quality_inspection_template", qc_doc.name, update_modified=False)
+		frappe.db.sql(""" update `tabItem Quality Inspection Parameter`
+			set parentfield = 'item_quality_inspection_parameter', parenttype = 'Quality Inspection Template',
+			parent = %s where parenttype = 'Item' and parent = %s""", (qc_doc.name, data.parent))
+
+	# update field in item variant settings
+	frappe.db.sql(""" update `tabVariant Field` set field_name = 'quality_inspection_template'
+		where field_name = 'quality_parameters'""")
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 274bb3e..04e1bf3 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -204,6 +204,7 @@
 				filters: {
 					docstatus: 1,
 					inspection_type: inspection_type,
+					reference_name: doc.name,
 					item_code: d.item_code
 				}
 			}
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 04f9df3..689089c 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -2694,37 +2694,35 @@
    "unique": 0
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)",
-   "description": "Will also apply to variants",
-   "fieldname": "quality_parameters",
-   "fieldtype": "Table",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "label": "Quality Parameters",
-   "length": 0,
-   "no_copy": 0,
-   "oldfieldname": "item_specification_details",
-   "oldfieldtype": "Table",
-   "options": "Item Quality Inspection Parameter",
-   "permlevel": 0,
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)", 
+   "fieldname": "quality_inspection_template", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Quality Inspection Template", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Quality Inspection Template", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
    "unique": 0
   },
   {
@@ -3545,7 +3543,7 @@
  "issingle": 0,
  "istable": 0,
  "max_attachments": 1,
- "modified": "2018-02-12 15:42:23.303090",
+ "modified": "2018-02-19 13:48:35.779089",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Item",
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.js b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
index 53579fb..aa9854a 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.js
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.js
@@ -3,13 +3,42 @@
 
 cur_frm.cscript.refresh = cur_frm.cscript.inspection_type;
 
+frappe.ui.form.on("Quality Inspection", {
+	item_code: function(frm) {
+		if (frm.doc.item_code) {
+			return frm.call({
+				method: "get_quality_inspection_template",
+				doc: frm.doc,
+				callback: function() {
+					refresh_field(['quality_inspection_template', 'readings']);
+				}
+			});
+		}
+	},
+
+	quality_inspection_template: function(frm) {
+		if (frm.doc.quality_inspection_template) {
+			return frm.call({
+				method: "get_item_specification_details",
+				doc: frm.doc,
+				callback: function() {
+					refresh_field('readings');
+				}
+			});
+		}
+	}
+})
+
 // 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";
+
 	if (doc.reference_type && doc.reference_name) {
 		return {
 			query: "erpnext.stock.doctype.quality_inspection.quality_inspection.item_query",
 			filters: {
-				"from": doc.reference_type + " Item",
+				"from": doctype,
 				"parent": doc.reference_name
 			}
 		}
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.json b/erpnext/stock/doctype/quality_inspection/quality_inspection.json
index 4dd109c..44d9a86 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.json
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.json
@@ -154,7 +154,7 @@
    "label": "Reference Type", 
    "length": 0, 
    "no_copy": 0, 
-   "options": "\nPurchase Receipt\nPurchase Invoice\nDelivery Note\nSales Invoice", 
+   "options": "\nPurchase Receipt\nPurchase Invoice\nDelivery Note\nSales Invoice\nStock Entry", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -547,6 +547,37 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "fieldname": "bom_no", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "BOM No", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "BOM", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "column_break_17", 
    "fieldtype": "Column Break", 
    "hidden": 0, 
@@ -670,8 +701,8 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "fieldname": "get_specification_details", 
-   "fieldtype": "Button", 
+   "fieldname": "quality_inspection_template", 
+   "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -679,11 +710,12 @@
    "in_global_search": 0, 
    "in_list_view": 0, 
    "in_standard_filter": 0, 
-   "label": "Get Specification Details", 
+   "label": "Quality Inspection Template", 
    "length": 0, 
    "no_copy": 0, 
-   "options": "get_item_specification_details", 
+   "options": "Quality Inspection Template", 
    "permlevel": 0, 
+   "precision": "", 
    "print_hide": 0, 
    "print_hide_if_no_value": 0, 
    "read_only": 0, 
@@ -738,7 +770,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-06-13 14:29:02.080120", 
+ "modified": "2018-02-17 00:53:43.899395", 
  "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 c3808f7..36f6405 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -3,50 +3,78 @@
 
 from __future__ import unicode_literals
 import frappe
-
-
 from frappe.model.document import Document
+from erpnext.stock.doctype.quality_inspection_template.quality_inspection_template \
+	import get_template_details
 
 class QualityInspection(Document):
+	def validate(self):
+		if not self.readings and self.item_code:
+			self.get_item_specification_details()
+
 	def get_item_specification_details(self):
+		if not self.quality_inspection_template:
+			self.quality_inspection_template = frappe.db.get_value('Item',
+				self.item_code, 'quality_inspection_template')
+
+		if not self.quality_inspection_template: return
+
 		self.set('readings', [])
-		variant_of = frappe.db.get_value("Item", self.item_code, "variant_of")
-		if variant_of:
-			specification = frappe.db.sql("select specification, value from `tabItem Quality Inspection Parameter` \
-				where parent in (%s, %s) order by idx", (self.item_code, variant_of))
-		else:
-			specification = frappe.db.sql("select specification, value from `tabItem Quality Inspection Parameter` \
-				where parent = %s order by idx", self.item_code)
-		for d in specification:
+		parameters = get_template_details(self.quality_inspection_template)
+		for d in parameters:
 			child = self.append('readings', {})
-			child.specification = d[0]
-			child.value = d[1]
-			child.status = 'Accepted'
+			child.specification = d.specification
+			child.value = d.value
+			child.status = "Accepted"
+
+	def get_quality_inspection_template(self):
+		template = ''
+		if self.bom_no:
+			template = frappe.db.get_value('BOM', self.bom_no, 'quality_inspection_template')
+
+		if not template:
+			template = frappe.db.get_value('BOM', self.item_code, 'quality_inspection_template')
+
+		self.quality_inspection_template = template
+		self.get_item_specification_details()
 
 	def on_submit(self):
+		self.update_qc_reference()
+
+	def on_cancel(self):
+		self.update_qc_reference()
+
+	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{doctype} Item` t1, `tab{doctype}` t2
+			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(doctype=self.reference_type),
-				(self.name, self.modified, self.reference_name, self.item_code))
-				
-	def on_cancel(self):
-		if self.reference_type and self.reference_name:
-			frappe.db.sql("""update `tab{doctype} Item` 
-				set quality_inspection = null, modified=%s 
-				where quality_inspection = %s"""
-				.format(doctype=self.reference_type), (self.modified, self.name))
-				
+				.format(parent_doc=self.reference_type, child_doc=doctype),
+				(quality_inspection, self.modified, self.reference_name, self.item_code))
+
 def item_query(doctype, txt, searchfield, start, page_len, filters):
 	if filters.get("from"):
 		from frappe.desk.reportview import get_match_cond
-		filters.update({
-			"txt": txt,
-			"mcond": get_match_cond(filters["from"]),
-			"start": start,
-			"page_len": page_len
-		})
-		return frappe.db.sql("""select item_code from `tab%(from)s`
-			where parent='%(parent)s' and docstatus < 2 and item_code like '%%%(txt)s%%' %(mcond)s
-			order by item_code limit %(start)s, %(page_len)s""" % filters)
+		mcond = get_match_cond(filters["from"])
+		cond = ""
+
+		if filters.get('from') in ['Purchase Invoice Item', 'Purchase Receipt Item']:
+			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']:
+			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"""
+
+		return frappe.db.sql(""" select item_code from `tab{doc}`
+			where parent=%(parent)s and docstatus < 2 and item_code like %(txt)s
+			and (quality_inspection is null or quality_inspection = '')
+			{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),
+			{'parent': filters.get('parent'), 'txt': "%%%s%%" % txt})
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.js b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.js
new file mode 100644
index 0000000..327484e
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Quality Inspection", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Quality Inspection
+		() => frappe.tests.make('Quality Inspection', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/stock/doctype/quality_inspection_template/__init__.py b/erpnext/stock/doctype/quality_inspection_template/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_template/__init__.py
diff --git a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.js b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.js
new file mode 100644
index 0000000..fa57a3d
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Quality Inspection Template', {
+	refresh: function() {
+
+	}
+});
diff --git a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.json b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.json
new file mode 100644
index 0000000..eab08e2
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.json
@@ -0,0 +1,186 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 1, 
+ "allow_rename": 1, 
+ "autoname": "field:quality_inspection_template_name", 
+ "beta": 0, 
+ "creation": "2018-01-24 16:23:41.691127", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "quality_inspection_template_name", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Quality Inspection Template Name", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "item_quality_inspection_parameter", 
+   "fieldtype": "Table", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Item Quality Inspection Parameter", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Item Quality Inspection Parameter", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2018-02-21 12:05:29.304432", 
+ "modified_by": "Administrator", 
+ "module": "Stock", 
+ "name": "Quality Inspection Template", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "System Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }, 
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "Stock User", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }, 
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "Quality Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }, 
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "Manufacturing User", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 0, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
new file mode 100644
index 0000000..0d9a903
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class QualityInspectionTemplate(Document):
+	pass
+
+def get_template_details(template):
+	if not template: return []
+
+	return frappe.get_all('Item Quality Inspection Parameter', fields=["specification", "value"],
+		filters={'parenttype': 'Quality Inspection Template', 'parent': template}, order_by="idx")
\ No newline at end of file
diff --git a/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.js b/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.js
new file mode 100644
index 0000000..879c262
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Quality Inspection Template", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Quality Inspection Template
+		() => frappe.tests.make('Quality Inspection Template', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.py b/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.py
new file mode 100644
index 0000000..b16efa8
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_template/test_quality_inspection_template.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import unittest
+
+class TestQualityInspectionTemplate(unittest.TestCase):
+	pass
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 9093946..825b4cb 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -57,7 +57,42 @@
 				}
 			}
 		});
+
+		frm.add_fetch("bom_no", "inspection_required", "inspection_required");
+		frm.trigger("setup_quality_inspection");
 	},
+
+	setup_quality_inspection: function(frm) {
+		if (!frm.doc.inspection_required) {
+			return;
+		}
+
+		let quality_inspection_field = frm.get_docfield("items", "quality_inspection");
+		quality_inspection_field.get_route_options_for_new_doc = function(row) {
+			if (frm.is_new()) return;
+			return {
+				"inspection_type": "Incoming",
+				"reference_type": frm.doc.doctype,
+				"reference_name": frm.doc.name,
+				"item_code": row.doc.item_code,
+				"description": row.doc.description,
+				"item_serial_no": row.doc.serial_no ? row.doc.serial_no.split("\n")[0] : null,
+				"batch_no": row.doc.batch_no
+			}
+		}
+
+		frm.set_query("quality_inspection", "items", function(doc, cdt, cdn) {
+			var d = locals[cdt][cdn];
+			return {
+				filters: {
+					docstatus: 1,
+					item_code: d.item_code,
+					reference_name: doc.name
+				}
+			}
+		});
+	},
+
 	refresh: function(frm) {
 		if(!frm.doc.docstatus) {
 			frm.add_custom_button(__('Make Material Request'), function() {
@@ -102,11 +137,11 @@
 			}, __("Get items from"));
 		}
 
-		if(frm.doc.company) {
+		if (frm.doc.company) {
 			frm.trigger("toggle_display_account_head");
 		}
 
-		if(frm.doc.docstatus==1 && frm.doc.purpose == "Material Receipt") {
+		if (frm.doc.docstatus==1 && frm.doc.purpose == "Material Receipt") {
 			frm.add_custom_button(__('Make Retention Stock Entry'), function () {
 				frm.trigger("make_retention_stock_entry");
 			});
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index f68690c..83bf92d 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -370,6 +370,37 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "fieldname": "inspection_required", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Inspection Required", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "col2", 
    "fieldtype": "Column Break", 
    "hidden": 0, 
@@ -1739,7 +1770,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-06-13 14:28:47.818067", 
+ "modified": "2018-02-17 10:32:24.111113", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Stock Entry", 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 9bccfad..6cb81d8 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -52,6 +52,7 @@
 		self.validate_finished_goods()
 		self.validate_with_material_request()
 		self.validate_batch()
+		self.validate_inspection()
 
 		if not self.from_bom:
 			self.fg_completed_qty = 0.0
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 2da9f35..8f287dd 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -11,7 +11,7 @@
 from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
 from erpnext.stock.stock_ledger import get_previous_sle
 from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
-from erpnext.stock.doctype.item.test_item import set_item_variant_settings, make_item_variant
+from erpnext.stock.doctype.item.test_item import set_item_variant_settings, make_item_variant, create_item
 from frappe.tests.test_permissions import set_user_permission_doctypes
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
 from erpnext.accounts.doctype.account.test_account import get_inventory_account
@@ -672,6 +672,24 @@
 		self.assertEquals(qty_in_usable_warehouse, 36)
 		self.assertEquals(qty_in_retention_warehouse, 4)
 
+	def test_quality_check(self):
+		item_code = "_Test Item For QC"
+		if not frappe.db.exists('Item', item_code):
+			create_item(item_code)
+
+		repack = frappe.copy_doc(test_records[3])
+		repack.inspection_required = 1
+		for d in repack.items:
+			if not d.s_warehouse and d.t_warehouse:
+				d.item_code = item_code
+				d.qty = 1
+				d.uom = "Nos"
+				d.stock_uom = "Nos"
+				d.basic_rate = 5000
+
+		repack.insert()
+		self.assertRaises(frappe.ValidationError, repack.submit)
+
 def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
 	se = frappe.copy_doc(test_records[0])
 	se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series"
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
index c7566d9..0f8bd17 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
@@ -994,6 +994,38 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "depends_on": "eval:parent.inspection_required && doc.t_warehouse", 
+   "fieldname": "quality_inspection", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Quality Inspection", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Quality Inspection", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "accounting", 
    "fieldtype": "Section Break", 
    "hidden": 0, 
@@ -1329,7 +1361,7 @@
  "issingle": 0, 
  "istable": 1, 
  "max_attachments": 0, 
- "modified": "2017-11-14 12:46:51.828176", 
+ "modified": "2018-02-16 20:19:57.471380", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Stock Entry Detail",