feat(jobs): add fp.job.step.timelog for granular timer tracking
Each button_start opens a fresh timelog row; button_finish closes the open row and recomputes step.duration_actual as the sum of all interval durations. Replicates Odoo MRP's mrp.workorder.time_ids granularity natively (no mrp dep). Schema: step_id (M2O cascade), user_id, date_started, date_finished, duration_minutes (computed, stored). ACLs: operator get create permission on timelogs because button_start creates them. Tests: test_start_creates_timelog (asserts the log row exists, date_finished is False, user_id is the current user) and test_finish_closes_timelog (asserts log gets date_finished, has a non-negative duration, and step.duration_actual matches). Manifest 19.0.8.5.1 -> 19.0.8.6.0. Part of: native job model migration (spec 2026-04-25) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
42
fusion_plating/fusion_plating/models/fp_job_step_timelog.py
Normal file
42
fusion_plating/fusion_plating/models/fp_job_step_timelog.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
#
|
||||
# fp.job.step.timelog — granular start/stop intervals for a step.
|
||||
#
|
||||
# Each step.button_start() opens a fresh timelog row. Each
|
||||
# step.button_finish() (or button_pause once added) closes the open
|
||||
# row. duration_actual on fp.job.step is the sum of these intervals.
|
||||
#
|
||||
# Replicates Odoo MRP's mrp.workorder.time_ids granularity natively
|
||||
# (without depending on the mrp module).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class FpJobStepTimeLog(models.Model):
|
||||
_name = 'fp.job.step.timelog'
|
||||
_description = 'Plating Job Step Time Log'
|
||||
_order = 'date_started desc'
|
||||
|
||||
step_id = fields.Many2one(
|
||||
'fp.job.step',
|
||||
required=True,
|
||||
ondelete='cascade',
|
||||
index=True,
|
||||
)
|
||||
user_id = fields.Many2one('res.users', required=True)
|
||||
date_started = fields.Datetime(required=True)
|
||||
date_finished = fields.Datetime()
|
||||
duration_minutes = fields.Float(
|
||||
compute='_compute_duration', store=True,
|
||||
)
|
||||
|
||||
@api.depends('date_started', 'date_finished')
|
||||
def _compute_duration(self):
|
||||
for log in self:
|
||||
if log.date_started and log.date_finished:
|
||||
delta = log.date_finished - log.date_started
|
||||
log.duration_minutes = delta.total_seconds() / 60.0
|
||||
else:
|
||||
log.duration_minutes = 0.0
|
||||
Reference in New Issue
Block a user