feat: Allowing operation level quality inspection check in BOM (backport #53859) (#54144)

Co-authored-by: Nishka Gosalia <58264710+nishkagosalia@users.noreply.github.com>
Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
This commit is contained in:
mergify[bot]
2026-04-09 02:02:35 +00:00
committed by GitHub
parent 526c8d0418
commit 233dc7c07b
7 changed files with 42 additions and 13 deletions

View File

@@ -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",

View File

@@ -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

View File

@@ -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",

View File

@@ -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):

View File

@@ -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",
)

View File

@@ -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",

View File

@@ -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