fix(jobs): auto-resync step.duration_actual on timelog edits

When a supervisor edits a timelog's date_started/date_finished (or
deletes a stale timelog), the parent step's "Actual Min" column
was showing stale data — duration_actual is a regular Float set
once by button_finish.

Adds:
- fp.job.step._fp_resum_duration_actual: quiet helper that re-sums
  duration_actual from time_log_ids.duration_minutes. Skip no-op
  updates so write traffic is minimised.
- fp.job.step.timelog.create/write/unlink hooks: call the helper
  on the affected parent step(s) so duration_actual stays
  consistent. Write hook only fires when date_started/date_finished/
  step_id changed (notes edits skip resync). step_id reassignment
  resyncs both old and new parent.
- Existing action_recompute_duration_from_timelogs (manual button)
  still posts a chatter entry for audit-trail use cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-11 23:53:45 -04:00
parent b0070afc1b
commit 1c68fd0555
4 changed files with 153 additions and 19 deletions

View File

@@ -3,7 +3,7 @@
# License OPL-1 (Odoo Proprietary License v1.0)
{
'name': 'Fusion Plating — Native Jobs',
'version': '19.0.8.20.1',
'version': '19.0.8.20.2',
'category': 'Manufacturing/Plating',
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
'author': 'Nexa Systems Inc.',

View File

@@ -320,16 +320,11 @@ class FpJobStep(models.Model):
return True
def action_recompute_duration_from_timelogs(self):
"""Re-sum duration_actual from the step's timelog rows.
Use case: supervisor adjusts a timelog row (back-date a forgotten
click, fix wrong operator, delete a stale entry that was left
open over a shift change) and needs the step's duration_actual
to reflect the corrected reality. Without this, edits to time_log_ids
rows don't propagate into duration_actual (which is set once
by button_finish).
Posts the before/after to chatter for audit.
"""Manual button — re-sum duration_actual + post to chatter
for audit. Use case: supervisor adjusts a timelog row and
wants an explicit audit trail of the recompute. The
automatic version called from timelog hooks is
_fp_resum_duration_actual (no chatter).
"""
for step in self:
old = step.duration_actual or 0.0
@@ -342,6 +337,16 @@ class FpJobStep(models.Model):
)) % (step.name, old, new, new - old, self.env.user.name))
return True
def _fp_resum_duration_actual(self):
"""Quiet re-sum — used by automatic triggers (timelog
create/write/unlink hooks). No chatter post. Skips no-op
updates so writes are minimised."""
for step in self:
new = sum(step.time_log_ids.mapped('duration_minutes'))
if abs((step.duration_actual or 0.0) - new) > 0.001:
step.duration_actual = new
return True
def action_finish_and_advance(self):
"""Steelhead-style "Finish & Next" — finish this step then auto-
start the next pending/ready step in sequence. Single click