feat(quality): Check quality status before receipt/delivery (#16169)

diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 7b3f740..63e89ab 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -12,6 +12,9 @@
 from erpnext.stock.stock_ledger import get_valuation_rate
 from erpnext.stock import get_warehouse_account_map
 
+class QualityInspectionRequiredError(frappe.ValidationError): pass
+class QualityInspectionRejectedError(frappe.ValidationError): pass
+
 class StockController(AccountsController):
 	def validate(self):
 		super(StockController, self).validate()
@@ -317,7 +320,6 @@
 	def validate_inspection(self):
 		'''Checks if quality inspection is set for Items that require inspection.
 		On submit, throw an exception'''
-
 		inspection_required_fieldname = None
 		if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
 			inspection_required_fieldname = "inspection_required_before_purchase"
@@ -330,17 +332,25 @@
 				return
 
 		for d in self.get('items'):
-			raise_exception = False
+			qa_required = 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
+				qa_required = True
 			elif self.doctype == "Stock Entry" and not d.quality_inspection and d.t_warehouse:
-				raise_exception = True
+				qa_required = True
 
-			if raise_exception:
+			if qa_required:
 				frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
 				if self.docstatus==1:
-					raise frappe.ValidationError
+					raise QualityInspectionRequiredError
+			elif self.docstatus == 1:
+				if d.quality_inspection:
+					qa_doc = frappe.get_doc("Quality Inspection", d.quality_inspection)
+					qa_failed = any([r.status=="Rejected" for r in qa_doc.readings])
+					if qa_failed:
+						frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}")
+							.format(d.idx, d.item_code), QualityInspectionRejectedError)
+
 
 	def update_blanket_order(self):
 		blanket_orders = list(set([d.blanket_order for d in self.items if d.blanket_order]))
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 24292f7..abdd676 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -392,4 +392,3 @@
 			"company": "_Test Company"
 		})
 		item.save()
-
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
index 1c8ec23..60cc9a0 100644
--- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
@@ -3,8 +3,45 @@
 
 import frappe
 import unittest
+from frappe.utils import nowdate
+from erpnext.stock.doctype.item.test_item import create_item
+from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+from erpnext.controllers.stock_controller import QualityInspectionRejectedError, QualityInspectionRequiredError
 
 # test_records = frappe.get_test_records('Quality Inspection')
 
 class TestQualityInspection(unittest.TestCase):
-	pass
+	def setUp(self):
+		create_item("_Test Item with QA")
+		frappe.db.set_value("Item", "_Test Item with QA", "inspection_required_before_delivery", 1)
+
+	def test_qa_for_delivery(self):
+		dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
+		self.assertRaises(QualityInspectionRequiredError, dn.submit)
+
+		qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected")
+		dn.reload()
+		self.assertRaises(QualityInspectionRejectedError, dn.submit)
+
+		frappe.db.set_value("Quality Inspection Reading", {"parent": qa.name}, "status", "Accepted")
+		dn.reload()
+		dn.submit()
+
+def create_quality_inspection(**args):
+	args = frappe._dict(args)
+	qa = frappe.new_doc("Quality Inspection")
+	qa.report_date = nowdate()
+	qa.inspection_type = args.inspection_type or "Outgoing"
+	qa.reference_type = args.reference_type
+	qa.reference_name = args.reference_name
+	qa.item_code = args.item_code or "_Test Item with QA"
+	qa.sample_size = 1
+	qa.inspected_by = frappe.session.user
+	qa.append("readings", {
+		"specification": "Size",
+		"status": args.status
+	})
+	qa.save()
+	qa.submit()
+
+	return qa
diff --git a/erpnext/templates/includes/itemised_tax_breakup.html b/erpnext/templates/includes/itemised_tax_breakup.html
index 982397e..c27e4ce 100644
--- a/erpnext/templates/includes/itemised_tax_breakup.html
+++ b/erpnext/templates/includes/itemised_tax_breakup.html
@@ -16,7 +16,7 @@
 				<tr>
 					<td>{{ item }}</td>
 					<td class='text-right'>
-						{{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, currency) }}
+						{{ frappe.utils.fmt_money(itemised_taxable_amount.get(item, 0), None, currency) }}
 					</td>
 					{% for tax_account in tax_accounts %}
 						{% set tax_details = taxes.get(tax_account) %}