fix(jobs): workflow bar stuck at Draft for confirmed/done jobs
Root cause: two compounding bugs in fp.job.workflow_state_id.
- The "Confirmed" state seed has no trigger fields set, so it
never passes _fp_is_passed_for_job.
- The _compute_workflow_state_id loop breaks on the first
non-passed state — so when Confirmed fails, every later
state stays unevaluated and the bar is stuck at Draft.
Fixes:
- Add trigger_on_job_state Selection field on fp.job.workflow.state
with values confirmed/in_progress/done. Passes when fp.job.state
>= the chosen value ("at least" semantics with explicit ordering
that treats on_hold==in_progress and cancelled outside the
progression). Lets workflow states key off the job's own state
when recipe default_kind tagging isn't present.
- Extend _fp_is_passed_for_job with the new branch.
- Change _compute_workflow_state_id from first-non-pass-breaks to
highest-passed-wins. Untagged/not-applicable states no longer
block the cascade — the bar shows the furthest milestone the
job has actually reached.
- Seed update (DB-side, since data is noupdate=1): Confirmed now
has trigger_on_job_state='confirmed'.
Result: Work Order # 00011 (state=confirmed, all 11 steps done/
skipped) now correctly shows the bar at "Done" instead of "Draft"
(via the existing trigger_all_steps_done on Done). Mid-flight
confirmed jobs without recipe tagging will show at least
"Confirmed" now.
Recipe authoring note (out of scope here): for accurate Received /
In Progress / Inspected intermediate states, recipe nodes still need
default_kind tagging (receiving / wet|bake|mask|rack / final_inspect).
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)
|
||||
{
|
||||
'name': 'Fusion Plating — Native Jobs',
|
||||
'version': '19.0.8.20.2',
|
||||
'version': '19.0.8.20.3',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
||||
'author': 'Nexa Systems Inc.',
|
||||
|
||||
@@ -115,11 +115,11 @@ class FpJob(models.Model):
|
||||
for job in self:
|
||||
passed = WS.browse()
|
||||
for ws in all_states:
|
||||
# Highest-passed semantics: untagged / not-applicable
|
||||
# states don't block the cascade. The bar reflects
|
||||
# the furthest milestone the job has actually reached.
|
||||
if ws._fp_is_passed_for_job(job):
|
||||
passed = ws
|
||||
else:
|
||||
# First non-passed state stops the bar's progress
|
||||
break
|
||||
job.workflow_state_id = passed
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@@ -141,6 +141,22 @@ class FpJobWorkflowState(models.Model):
|
||||
'customer pickup) independently from plating steps.',
|
||||
)
|
||||
|
||||
trigger_on_job_state = fields.Selection(
|
||||
[
|
||||
('confirmed', 'Job Confirmed'),
|
||||
('in_progress', 'Job In Progress'),
|
||||
('done', 'Job Done'),
|
||||
],
|
||||
string='Trigger on Job State',
|
||||
help='State-driven trigger: this milestone passes when '
|
||||
'fp.job.state reaches AT LEAST the chosen value. Fallback '
|
||||
'for jobs whose recipes do not tag steps with default_kind '
|
||||
'(so default_kind-driven triggers cannot fire). Order: '
|
||||
'draft < confirmed < in_progress/on_hold < done. '
|
||||
'Use for Confirmed ("confirmed") and optionally as a '
|
||||
'safety-net for Done ("done").',
|
||||
)
|
||||
|
||||
block_when_quality_hold = fields.Boolean(
|
||||
string='Blocked by Quality Hold',
|
||||
default=False,
|
||||
@@ -198,6 +214,19 @@ class FpJobWorkflowState(models.Model):
|
||||
job.delivery_id and job.delivery_id.state == 'delivered'
|
||||
)
|
||||
|
||||
# Special trigger: job.state reached ("at least" semantics).
|
||||
if self.trigger_on_job_state:
|
||||
order = {
|
||||
'draft': 0,
|
||||
'confirmed': 1,
|
||||
'in_progress': 2,
|
||||
'on_hold': 2,
|
||||
'done': 3,
|
||||
}
|
||||
required = order.get(self.trigger_on_job_state, -1)
|
||||
actual = order.get(job.state, -1)
|
||||
return required >= 0 and actual >= required
|
||||
|
||||
# Special trigger: first wet step started
|
||||
if self.trigger_first_step_started:
|
||||
wet_kinds = ('wet', 'bake', 'mask', 'rack')
|
||||
|
||||
Reference in New Issue
Block a user