diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json index 11c704649a3..ad47d4024b4 100644 --- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json +++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json @@ -20,6 +20,7 @@ "is_subcontracted", "is_final_finished_good", "set_cost_based_on_bom_qty", + "quality_inspection_required", "warehouse_section", "skip_material_transfer", "backflush_from_wip_warehouse", @@ -290,13 +291,20 @@ "fieldname": "backflush_from_wip_warehouse", "fieldtype": "Check", "label": "Backflush Materials From WIP Warehouse" + }, + { + "default": "0", + "depends_on": "eval:parent.inspection_required", + "fieldname": "quality_inspection_required", + "fieldtype": "Check", + "label": "Quality Inspection Required" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2026-03-31 17:09:48.771834", + "modified": "2026-04-01 17:09:48.771834", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Operation", diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py index fd197e89e62..72d7f194fd8 100644 --- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py +++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py @@ -35,6 +35,7 @@ class BOMOperation(Document): parent: DF.Data parentfield: DF.Data parenttype: DF.Data + quality_inspection_required: DF.Check sequence_id: DF.Int set_cost_based_on_bom_qty: DF.Check skip_material_transfer: DF.Check diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index a4eaec8e73f..9716ae49dc0 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -788,27 +788,27 @@ class JobCard(Document): ["action_if_quality_inspection_is_not_submitted", "action_if_quality_inspection_is_rejected"], ) - item = self.finished_good or self.production_item - bom_inspection_required = frappe.db.get_value( - "BOM", self.semi_fg_bom or self.bom_no, "inspection_required" + bom_inspection_required = frappe.get_value("BOM", self.bom_no, "inspection_required") + operation_inspection_required = frappe.get_value( + "Work Order Operation", self.operation_id, "quality_inspection_required" ) - if bom_inspection_required: + if bom_inspection_required and operation_inspection_required: if not self.quality_inspection: frappe.throw( _( "Quality Inspection is required for the item {0} before completing the job card {1}" - ).format(get_link_to_form("Item", item), bold(self.name)) + ).format(get_link_to_form("Item", self.finished_good), bold(self.name)) ) - qa_status, docstatus = frappe.db.get_value( + + qa_status, docstatus = frappe.get_value( "Quality Inspection", self.quality_inspection, ["status", "docstatus"] ) - if docstatus != 1: if action_submit == "Stop": frappe.throw( _("Quality Inspection {0} is not submitted for the item: {1}").format( get_link_to_form("Quality Inspection", self.quality_inspection), - get_link_to_form("Item", item), + get_link_to_form("Item", self.finished_good), ), title=_("Inspection Submission"), exc=QualityInspectionNotSubmittedError, @@ -817,7 +817,7 @@ class JobCard(Document): frappe.msgprint( _("Quality Inspection {0} is not submitted for the item: {1}").format( get_link_to_form("Quality Inspection", self.quality_inspection), - get_link_to_form("Item", item), + get_link_to_form("Item", self.finished_good), ), alert=True, indicator="orange", @@ -827,7 +827,7 @@ class JobCard(Document): frappe.throw( _("Quality Inspection {0} is rejected for the item: {1}").format( get_link_to_form("Quality Inspection", self.quality_inspection), - get_link_to_form("Item", item), + get_link_to_form("Item", self.finished_good), ), title=_("Inspection Rejected"), exc=QualityInspectionRejectedError, @@ -836,7 +836,7 @@ class JobCard(Document): frappe.msgprint( _("Quality Inspection {0} is rejected for the item: {1}").format( get_link_to_form("Quality Inspection", self.quality_inspection), - get_link_to_form("Item", item), + get_link_to_form("Item", self.finished_good), ), alert=True, indicator="orange", diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py index a25b6e1af3d..9a6733232a1 100644 --- a/erpnext/manufacturing/doctype/job_card/test_job_card.py +++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py @@ -87,6 +87,7 @@ class TestJobCard(ERPNextTestSuite): with_operations=1, track_semi_finished_goods=1, company="_Test Company", + inspection_required=1, ) final_bom.append("items", {"item_code": raw.name, "qty": 1}) final_bom.append( @@ -97,6 +98,7 @@ class TestJobCard(ERPNextTestSuite): "bom_no": cut_bom, "skip_material_transfer": 1, "time_in_mins": 60, + "quality_inspection_required": 1, }, ) final_bom.append( @@ -133,6 +135,15 @@ class TestJobCard(ERPNextTestSuite): work_order.submit() job_card = frappe.get_all("Job Card", filters={"work_order": work_order.name, "operation": "Cutting"}) job_card_doc = frappe.get_doc("Job Card", job_card[0].name) + job_card_doc.append( + "time_logs", + { + "from_time": "2024-01-01 08:00:00", + "to_time": "2024-01-01 09:00:00", + "time_in_mins": 60, + "completed_qty": 1, + }, + ) self.assertRaises(frappe.ValidationError, job_card_doc.submit) def test_job_card_operations(self): diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 5e18f68e8c0..19185a6ec58 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -1277,6 +1277,7 @@ class WorkOrder(Document): "skip_material_transfer", "backflush_from_wip_warehouse", "set_cost_based_on_bom_qty", + "quality_inspection_required", ], order_by="idx", ) diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json index 6cbcc855d01..89ed830116b 100644 --- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json +++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json @@ -15,6 +15,7 @@ "workstation_type", "workstation", "sequence_id", + "quality_inspection_required", "section_break_insy", "bom_no", "finished_good", @@ -294,13 +295,19 @@ "fieldtype": "Check", "label": "Backflush Materials From WIP Warehouse", "read_only": 1 + }, + { + "default": "0", + "fieldname": "quality_inspection_required", + "fieldtype": "Check", + "label": "Quality Inspection Required" } ], "grid_page_length": 50, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2025-05-15 15:10:06.885440", + "modified": "2026-03-30 17:20:08.874381", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order Operation", diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py index fb8b3feb4dd..2e45434f94b 100644 --- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py +++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py @@ -36,6 +36,7 @@ class WorkOrderOperation(Document): planned_operating_cost: DF.Currency planned_start_time: DF.Datetime | None process_loss_qty: DF.Float + quality_inspection_required: DF.Check sequence_id: DF.Int skip_material_transfer: DF.Check source_warehouse: DF.Link | None