[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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user