feat(fusion_plating_jobs): late_risk_ratio + active_step_id computes on fp.job
Plan tasks P2.2 + P2.3 batched (both small additive computes on fp.job;
local tests not run between them — entech verifies).
late_risk_ratio — stored Float, remaining_planned / minutes_to_deadline.
Drives the Manager At-Risk view (Phase 4).
Recomputes on step state, duration, deadline changes.
active_step_id — non-stored Many2one. Currently in_progress step
(lowest sequence if multiple — defensive).
Drives JobWorkspace landing focus.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,57 @@ class FpJob(models.Model):
|
||||
tail = raw.rsplit('/', 1)[-1]
|
||||
job.display_wo_name = f'WO # {tail}'
|
||||
|
||||
# Phase 2 — At-Risk view + Workspace landing focus.
|
||||
late_risk_ratio = fields.Float(
|
||||
compute='_compute_late_risk_ratio',
|
||||
store=True,
|
||||
string='Late-risk Ratio',
|
||||
help='remaining_planned_minutes / minutes_to_deadline. '
|
||||
'>1.0 means the job will be late if nothing changes. '
|
||||
'Drives the At-Risk view on the manager dashboard.',
|
||||
)
|
||||
active_step_id = fields.Many2one(
|
||||
'fp.job.step',
|
||||
compute='_compute_active_step_id',
|
||||
string='Active Step',
|
||||
help='Currently in-progress step (lowest sequence if multiple — '
|
||||
'defensive). Drives JobWorkspace landing focus.',
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
'date_deadline',
|
||||
'step_ids.state',
|
||||
'step_ids.duration_expected',
|
||||
)
|
||||
def _compute_late_risk_ratio(self):
|
||||
from datetime import datetime
|
||||
for job in self:
|
||||
if not job.date_deadline:
|
||||
job.late_risk_ratio = 0.0
|
||||
continue
|
||||
open_steps = job.step_ids.filtered(
|
||||
lambda s: s.state not in ('done', 'skipped', 'cancelled')
|
||||
)
|
||||
remaining_planned = sum(open_steps.mapped('duration_expected') or [0])
|
||||
if remaining_planned <= 0:
|
||||
job.late_risk_ratio = 0.0
|
||||
continue
|
||||
now = datetime.now()
|
||||
# date_deadline is naive UTC in Odoo; compare directly
|
||||
minutes_to_deadline = max(
|
||||
1.0,
|
||||
(job.date_deadline - now).total_seconds() / 60.0,
|
||||
)
|
||||
job.late_risk_ratio = remaining_planned / minutes_to_deadline
|
||||
|
||||
@api.depends('step_ids.state', 'step_ids.sequence')
|
||||
def _compute_active_step_id(self):
|
||||
for job in self:
|
||||
active = job.step_ids.filtered(
|
||||
lambda s: s.state == 'in_progress'
|
||||
).sorted('sequence')
|
||||
job.active_step_id = active[:1].id if active else False
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Sub 14 — Configurable workflow state (status bar milestone)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user