Merge branch 'develop' into fix/quality-inspection/status
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.json b/erpnext/stock/doctype/quality_inspection/quality_inspection.json
index edfe7e9..db9322f 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.json
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.json
@@ -10,6 +10,7 @@
   "naming_series",
   "report_date",
   "status",
+  "manual_inspection",
   "column_break_4",
   "inspection_type",
   "reference_type",
@@ -231,6 +232,12 @@
    "label": "Status",
    "options": "\nAccepted\nRejected",
    "reqd": 1
+  },
+  {
+   "default": "0",
+   "fieldname": "manual_inspection",
+   "fieldtype": "Check",
+   "label": "Manual Inspection"
   }
  ],
  "icon": "fa fa-search",
@@ -238,10 +245,11 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-12-18 19:59:55.710300",
+ "modified": "2022-10-04 22:00:13.995221",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Quality Inspection",
+ "naming_rule": "By \"Naming Series\" field",
  "owner": "Administrator",
  "permissions": [
   {
@@ -262,5 +270,6 @@
  "search_fields": "item_code, report_date, reference_name",
  "show_name_in_global_search": 1,
  "sort_field": "modified",
- "sort_order": "ASC"
+ "sort_order": "ASC",
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index 13abfad..8ffd3f2 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -30,6 +30,9 @@
 		if self.readings:
 			self.inspect_and_set_status()
 
+	def before_submit(self):
+		self.validate_readings_status_mandatory()
+
 	@frappe.whitelist()
 	def get_item_specification_details(self):
 		if not self.quality_inspection_template:
@@ -65,6 +68,11 @@
 	def on_cancel(self):
 		self.update_qc_reference()
 
+	def validate_readings_status_mandatory(self):
+		for reading in self.readings:
+			if not reading.status:
+				frappe.throw(_("Row #{0}: Status is mandatory").format(reading.idx))
+
 	def update_qc_reference(self):
 		quality_inspection = self.name if self.docstatus == 1 else ""
 
@@ -124,6 +132,16 @@
 					# if not formula based check acceptance values set
 					self.set_status_based_on_acceptance_values(reading)
 
+		if not self.manual_inspection:
+			self.status = "Accepted"
+			for reading in self.readings:
+				if reading.status == "Rejected":
+					self.status = "Rejected"
+					frappe.msgprint(
+						_("Status set to rejected as there are one or more rejected readings."), alert=True
+					)
+					break
+
 	def set_status_based_on_acceptance_values(self, reading):
 		if not cint(reading.numeric):
 			result = reading.get("reading_value") == reading.get("value")
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
index 144f138..4f19643 100644
--- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
@@ -160,7 +160,7 @@
 		)
 
 		readings = [
-			{"specification": "Iron Content", "min_value": 0.1, "max_value": 0.9, "reading_1": "0.4"}
+			{"specification": "Iron Content", "min_value": 0.1, "max_value": 0.9, "reading_1": "1.0"}
 		]
 
 		qa = create_quality_inspection(
@@ -184,6 +184,38 @@
 		se.cancel()
 		frappe.db.set_value("Stock Settings", None, "action_if_quality_inspection_is_rejected", "Stop")
 
+	def test_qi_status(self):
+		make_stock_entry(
+			item_code="_Test Item with QA", target="_Test Warehouse - _TC", qty=1, basic_rate=100
+		)
+		dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
+		qa = create_quality_inspection(
+			reference_type="Delivery Note", reference_name=dn.name, status="Accepted", do_not_save=True
+		)
+		qa.readings[0].manual_inspection = 1
+		qa.save()
+
+		# Case - 1: When there are one or more readings with rejected status and parent manual inspection is unchecked, then parent status should be set to rejected.
+		qa.status = "Accepted"
+		qa.manual_inspection = 0
+		qa.readings[0].status = "Rejected"
+		qa.save()
+		self.assertEqual(qa.status, "Rejected")
+
+		# Case - 2: When all readings have accepted status and parent manual inspection is unchecked, then parent status should be set to accepted.
+		qa.status = "Rejected"
+		qa.manual_inspection = 0
+		qa.readings[0].status = "Accepted"
+		qa.save()
+		self.assertEqual(qa.status, "Accepted")
+
+		# Case - 3: When parent manual inspection is checked, then parent status should not be changed.
+		qa.status = "Accepted"
+		qa.manual_inspection = 1
+		qa.readings[0].status = "Rejected"
+		qa.save()
+		self.assertEqual(qa.status, "Accepted")
+
 
 def create_quality_inspection(**args):
 	args = frappe._dict(args)