fix(jobs): make "In Progress" workflow milestone fire reliably
Two coupled fixes so the workflow bar shows "In Progress" when work
is actually underway, even on recipes without kind tagging:
B. Auto-promote fp.job.state on first step start.
fp.job.step.write hook detects step transitions to in_progress
and promotes parent job state from 'confirmed' → 'in_progress'.
Without this, fp.job.state never reached 'in_progress' anywhere
in the codebase, so the trigger_on_job_state='in_progress'
path was dead code.
C. Smarter trigger_first_step_started for untagged recipes.
For tagged recipes (any step has kind in wet/bake/mask/rack),
keep the strict kind-based check. For untagged recipes (all
steps kind='other' or similar), fall back to "any step in
in_progress/paused/done" so the milestone fires regardless of
recipe authoring quality.
Verified end-to-end on entech with untagged steps:
- confirmed → in_progress when first step starts
- workflow bar tracks at in_progress through the work
- workflow bar advances to done when all steps done/skipped
Recipe authoring still encouraged for full Received / Inspected
intermediate states (those keep their default_kind triggers).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
{
|
{
|
||||||
'name': 'Fusion Plating — Native Jobs',
|
'name': 'Fusion Plating — Native Jobs',
|
||||||
'version': '19.0.8.20.3',
|
'version': '19.0.8.20.4',
|
||||||
'category': 'Manufacturing/Plating',
|
'category': 'Manufacturing/Plating',
|
||||||
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
||||||
'author': 'Nexa Systems Inc.',
|
'author': 'Nexa Systems Inc.',
|
||||||
|
|||||||
@@ -174,6 +174,18 @@ class FpJobStep(models.Model):
|
|||||||
'(state=%s) by %s.'
|
'(state=%s) by %s.'
|
||||||
)) % (step.name, old_name, new_name, step.state,
|
)) % (step.name, old_name, new_name, step.state,
|
||||||
self.env.user.name))
|
self.env.user.name))
|
||||||
|
|
||||||
|
# Auto-promote parent job: confirmed → in_progress on first
|
||||||
|
# step start. Without this, fp.job.state never reaches
|
||||||
|
# 'in_progress' anywhere in the codebase, so the In Progress
|
||||||
|
# workflow milestone (trigger_on_job_state='in_progress')
|
||||||
|
# never fires.
|
||||||
|
if vals.get('state') == 'in_progress':
|
||||||
|
jobs_to_promote = self.mapped('job_id').filtered(
|
||||||
|
lambda j: j.state == 'confirmed'
|
||||||
|
)
|
||||||
|
if jobs_to_promote:
|
||||||
|
jobs_to_promote.write({'state': 'in_progress'})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
|
|||||||
@@ -227,18 +227,28 @@ class FpJobWorkflowState(models.Model):
|
|||||||
actual = order.get(job.state, -1)
|
actual = order.get(job.state, -1)
|
||||||
return required >= 0 and actual >= required
|
return required >= 0 and actual >= required
|
||||||
|
|
||||||
# Special trigger: first wet step started
|
# Special trigger: first wet step started.
|
||||||
|
# For tagged recipes (any step has kind in wet/bake/mask/rack),
|
||||||
|
# use strict kind-based check. For untagged recipes (all steps
|
||||||
|
# are kind='other'), fall back to "any step started" so the
|
||||||
|
# milestone fires regardless of recipe authoring quality.
|
||||||
if self.trigger_first_step_started:
|
if self.trigger_first_step_started:
|
||||||
wet_kinds = ('wet', 'bake', 'mask', 'rack')
|
wet_kinds = ('wet', 'bake', 'mask', 'rack')
|
||||||
production_started = any(
|
has_kind_tagging = any(s.kind in wet_kinds for s in steps)
|
||||||
s.state in ('in_progress', 'paused', 'done')
|
if has_kind_tagging:
|
||||||
and (s.kind in wet_kinds)
|
production_started = any(
|
||||||
for s in steps
|
s.state in ('in_progress', 'paused', 'done')
|
||||||
)
|
and (s.kind in wet_kinds)
|
||||||
if not production_started:
|
for s in steps
|
||||||
return False
|
)
|
||||||
# Production milestone — not blocked by quality hold here
|
else:
|
||||||
return True
|
# Untagged recipe — any started step counts as
|
||||||
|
# "production has started".
|
||||||
|
production_started = any(
|
||||||
|
s.state in ('in_progress', 'paused', 'done')
|
||||||
|
for s in steps
|
||||||
|
)
|
||||||
|
return production_started
|
||||||
|
|
||||||
# Standard trigger: ALL recipe steps matching the trigger
|
# Standard trigger: ALL recipe steps matching the trigger
|
||||||
# (default_kind in our list OR per-node override pointing at
|
# (default_kind in our list OR per-node override pointing at
|
||||||
|
|||||||
Reference in New Issue
Block a user