[FIX] mrp(workorder_hr): fix workorder times

Fix workorder times problems:
- sum in workorders list view
  (displays numeric value rather than mins:secs)
- timers sometimes starts at -00:01
- almost all tablet view actions reset the timer (click burger, ...)
- clicking pause stops the timer at the next second
- seconds are lost in employee timers

Task: 2985735
X-original-commit: 7dceef12771890f9fb9fa554e70414c622053ced
Part-of: odoo/odoo#106908
This commit is contained in:
JF Aubert
2022-12-01 14:33:57 +01:00
parent 42f9a2c2da
commit b7e499473c
3 changed files with 47 additions and 32 deletions
+6 -7
View File
@@ -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
+8
View File
@@ -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
+33 -25
View File
@@ -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);