diff --git a/fusion_plating/fusion_plating_bridge_mrp/models/mrp_production.py b/fusion_plating/fusion_plating_bridge_mrp/models/mrp_production.py index 4bbb22f3..0c9c13ae 100644 --- a/fusion_plating/fusion_plating_bridge_mrp/models/mrp_production.py +++ b/fusion_plating/fusion_plating_bridge_mrp/models/mrp_production.py @@ -495,8 +495,8 @@ class MrpProduction(models.Model): """ WorkOrder = self.env['mrp.workorder'] for production in self: - if not production.x_fc_recipe_id: - continue # No recipe assigned + if not production._resolve_mo_process_tree(): + continue # No recipe / part tree assigned if production.workorder_ids: continue # WOs already exist — don't duplicate @@ -679,7 +679,11 @@ class MrpProduction(models.Model): # 'step' nodes at top level are handled by their parent operation # Start walking from recipe root - walk_node(production.x_fc_recipe_id) + # Sub 3 — resolve via helper (part-cloned tree preferred, + # recipe_id fallback) + root = production._resolve_mo_process_tree() + if root: + walk_node(root) # Bulk create work orders if wo_vals_list: @@ -699,7 +703,7 @@ class MrpProduction(models.Model): ) production.message_post( body=_('%d work orders generated from recipe "%s".') % ( - len(wo_vals_list), production.x_fc_recipe_id.name), + len(wo_vals_list), (root.name if root else '')), ) # ------------------------------------------------------------------ @@ -1146,6 +1150,37 @@ class MrpProduction(models.Model): 'target': 'current', } + # ------------------------------------------------------------------ + # Sub 3 — Process tree resolution (single source for WO walker) + # ------------------------------------------------------------------ + def _resolve_mo_process_tree(self): + """Resolve which process-tree root to walk for this MO. + + Sub 3 — prefers the linked part's cloned tree + (SO line's x_fc_part_catalog_id.default_process_id); falls back + to the legacy x_fc_recipe_id for MOs without a linked part or + without a composed part tree. + + Single entry point so Sub 4 / Sub 5 updates touch one method. + """ + self.ensure_one() + # Resolve part via SO lines (MO's origin → sale.order → first + # line's part). mrp.production has no direct part link; the + # relationship lives on sale.order.line. + part = False + if self.origin: + so = self.env['sale.order'].search( + [('name', '=', self.origin)], limit=1, + ) + if so and so.order_line: + first_line = so.order_line[0] + if 'x_fc_part_catalog_id' in first_line._fields: + part = first_line.x_fc_part_catalog_id + if part and part.default_process_id: + return part.default_process_id + # Fallback — legacy recipe lookup (coating config / product match) + return self.x_fc_recipe_id + # ------------------------------------------------------------------ # Sub 2 — Certificate requirement resolution (single source) # ------------------------------------------------------------------