diff --git a/addons/mrp/models/mrp_workcenter.py b/addons/mrp/models/mrp_workcenter.py index d8a30a9505d..b5bea7bdcf6 100644 --- a/addons/mrp/models/mrp_workcenter.py +++ b/addons/mrp/models/mrp_workcenter.py @@ -2,9 +2,8 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from dateutil import relativedelta -from datetime import timedelta +from datetime import timedelta, datetime from functools import partial -import datetime from pytz import timezone from random import randint @@ -90,7 +89,7 @@ class MrpWorkcenter(models.Model): result_duration_expected = {wid: 0 for wid in self._ids} # Count Late Workorder data = MrpWorkorder._read_group( - [('workcenter_id', 'in', self.ids), ('state', 'in', ('pending', 'waiting', 'ready')), ('date_planned_start', '<', datetime.datetime.now().strftime('%Y-%m-%d'))], + [('workcenter_id', 'in', self.ids), ('state', 'in', ('pending', 'waiting', 'ready')), ('date_planned_start', '<', datetime.now().strftime('%Y-%m-%d'))], ['workcenter_id'], ['workcenter_id']) count_data = dict((item['workcenter_id'][0], item['workcenter_id_count']) for item in data) # Count All, Pending, Ready, Progress Workorder @@ -133,7 +132,7 @@ class MrpWorkcenter(models.Model): def _compute_blocked_time(self): # TDE FIXME: productivity loss type should be only losses, probably count other time logs differently ?? data = self.env['mrp.workcenter.productivity']._read_group([ - ('date_start', '>=', fields.Datetime.to_string(datetime.datetime.now() - relativedelta.relativedelta(months=1))), + ('date_start', '>=', fields.Datetime.to_string(datetime.now() - relativedelta.relativedelta(months=1))), ('workcenter_id', 'in', self.ids), ('date_end', '!=', False), ('loss_type', '!=', 'productive')], @@ -145,7 +144,7 @@ class MrpWorkcenter(models.Model): def _compute_productive_time(self): # TDE FIXME: productivity loss type should be only losses, probably count other time logs differently data = self.env['mrp.workcenter.productivity']._read_group([ - ('date_start', '>=', fields.Datetime.to_string(datetime.datetime.now() - relativedelta.relativedelta(months=1))), + ('date_start', '>=', fields.Datetime.to_string(datetime.now() - relativedelta.relativedelta(months=1))), ('workcenter_id', 'in', self.ids), ('date_end', '!=', False), ('loss_type', '=', 'productive')], @@ -164,7 +163,7 @@ class MrpWorkcenter(models.Model): def _compute_performance(self): wo_data = self.env['mrp.workorder']._read_group([ - ('date_start', '>=', fields.Datetime.to_string(datetime.datetime.now() - relativedelta.relativedelta(months=1))), + ('date_start', '>=', fields.Datetime.to_string(datetime.now() - relativedelta.relativedelta(months=1))), ('workcenter_id', 'in', self.ids), ('state', '=', 'done')], ['duration_expected', 'workcenter_id', 'duration'], ['workcenter_id'], lazy=False) duration_expected = dict((data['workcenter_id'][0], data['duration_expected']) for data in wo_data) @@ -190,7 +189,7 @@ class MrpWorkcenter(models.Model): if self.working_state != 'blocked': raise exceptions.UserError(_("It has already been unblocked.")) times = self.env['mrp.workcenter.productivity'].search([('workcenter_id', '=', self.id), ('date_end', '=', False)]) - times.write({'date_end': fields.Datetime.now()}) + times.write({'date_end': datetime.now()}) return {'type': 'ir.actions.client', 'tag': 'reload'} @api.model_create_multi diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py index 8f8945213d9..77329c89a43 100644 --- a/addons/mrp/models/mrp_workorder.py +++ b/addons/mrp/models/mrp_workorder.py @@ -863,3 +863,11 @@ class MrpWorkorder(models.Model): self.ensure_one() if self.qty_producing: self.qty_producing = quantity + + def get_working_duration(self): + """Get the additional duration for 'open times' i.e. productivity lines with no date_end.""" + self.ensure_one() + duration = 0 + for time in self.time_ids.filtered(lambda time: not time.date_end): + duration += (datetime.now() - time.date_start).total_seconds() / 60 + return duration diff --git a/addons/mrp/static/src/widgets/timer.js b/addons/mrp/static/src/widgets/timer.js index 0e64226be2a..a17b409d4d7 100644 --- a/addons/mrp/static/src/widgets/timer.js +++ b/addons/mrp/static/src/widgets/timer.js @@ -1,14 +1,31 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; import { parseFloatTime } from "@web/views/fields/parsers"; import { useInputField } from "@web/views/fields/input_field_hook"; import { standardFieldProps } from "@web/views/fields/standard_field_props"; const { Component, useState, onWillUpdateProps, onWillStart, onWillDestroy } = owl; +function formatMinutes(value) { + if (value === false) { + return ""; + } + const isNegative = value < 0; + if (isNegative) { + value = Math.abs(value); + } + let min = Math.floor(value); + let sec = Math.floor((value % 1) * 60); + sec = `${sec}`.padStart(2, "0"); + min = `${min}`.padStart(2, "0"); + return `${isNegative ? "-" : ""}${min}:${sec}`; +} + export class MrpTimer extends Component { setup() { + this.orm = useService('orm'); this.state = useState({ // duration is expected to be given in minutes duration: @@ -25,9 +42,16 @@ export class MrpTimer extends Component { ? this.props.ongoing : this.props.record.data.is_user_working; - onWillStart(() => this._runTimer()); + onWillStart(async () => { + if(this.props.ongoing === undefined && this.props.record.data.state == "progress") { + const additionalDuration = await this.orm.call('mrp.workorder', 'get_working_duration', [this.props.record.resId]); + this.state.duration += additionalDuration; + } + if (this.ongoing) { + this._runTimer(); + } + }); onWillUpdateProps((nextProps) => { - this.state.duration = nextProps.value; const newOngoing = "ongoing" in nextProps ? nextProps.ongoing @@ -35,6 +59,7 @@ export class MrpTimer extends Component { const rerun = !this.ongoing && newOngoing; this.ongoing = newOngoing; if (rerun) { + this.state.duration = nextProps.value; this._runTimer(); } }); @@ -42,34 +67,16 @@ export class MrpTimer extends Component { } get durationFormatted() { - return this._formatMinutes(); + return formatMinutes(this.state.duration); } _runTimer() { - if (this.ongoing) { - this.timer = setTimeout(() => { + this.timer = setTimeout(() => { + if (this.ongoing) { this.state.duration += 1 / 60; this._runTimer(); - }, 1000); - } - } - - _formatMinutes() { - let value = this.state.duration; - if (value === false) { - return ""; - } - const isNegative = value < 0; - if (isNegative) { - value = Math.abs(value); - } - let min = Math.floor(value); - // Although looking quite overkill, the following line ensures that we do - // not have float issues while still considering that 59s is 00:00. - let sec = Math.floor(Math.round((value % 1) * 60)); - sec = `${sec}`.padStart(2, "0"); - min = `${min}`.padStart(2, "0"); - return `${isNegative ? "-" : ""}${min}:${sec}`; + } + }, 1000); } } @@ -83,3 +90,4 @@ MrpTimer.props = { MrpTimer.template = "mrp.MrpTimer"; registry.category("fields").add("mrp_timer", MrpTimer); +registry.category("formatters").add("mrp_timer", formatMinutes); \ No newline at end of file