From 2d3a44e6bd725e87432ebd62eeb3096d486d834b Mon Sep 17 00:00:00 2001 From: "Xavier Bol (xbo)" Date: Mon, 9 Dec 2019 12:25:13 +0100 Subject: [PATCH] [FIX] hr_timesheet: problem desynchronization time between server and client TaskID: 2088586 When we launch the timer, if the clock of the client isn't correctly synchronize with internet, we can't correctly display the timer, because the clock of the server can be in advance. The solution is to call the server to have this time and use the timer only with the time of the server. --- addons/hr_timesheet/models/timer_mixin.py | 9 ++++ addons/hr_timesheet/static/src/js/Timer.js | 23 ++++++++++ addons/hr_timesheet/static/src/js/timer.js | 46 +++++++++---------- .../static/src/js/timesheet_uom.js | 21 +++------ 4 files changed, 62 insertions(+), 37 deletions(-) diff --git a/addons/hr_timesheet/models/timer_mixin.py b/addons/hr_timesheet/models/timer_mixin.py index 71f916c5dd2..319d020a66e 100644 --- a/addons/hr_timesheet/models/timer_mixin.py +++ b/addons/hr_timesheet/models/timer_mixin.py @@ -65,3 +65,12 @@ class TimerMixin(models.AbstractModel): def action_timer_resume(self) -> None: new_start = self.timer_start + (fields.Datetime.now() - self.timer_pause) self.write({'timer_start': new_start, 'timer_pause': False}) + + def get_server_time(self): + """ Get the time of the server + + The problem with the timer, it's the time can be different between server side and client side. + We need to have the time of the server and don't use the local time. Then, we have a timer beginning at 0:00 + and not 23:59 or something else. + """ + return fields.Datetime.now() diff --git a/addons/hr_timesheet/static/src/js/Timer.js b/addons/hr_timesheet/static/src/js/Timer.js index 0c2c6baa7c2..c2cbabc5834 100644 --- a/addons/hr_timesheet/static/src/js/Timer.js +++ b/addons/hr_timesheet/static/src/js/Timer.js @@ -12,6 +12,10 @@ odoo.define('hr_timesheet.Timer', function (require) { this.seconds = seconds; } + /** + * Convert float to time + * @param {number} float + */ static convertFloatToTime(float) { if (float === 0) { return new Timer(0, 0, 0); @@ -24,6 +28,25 @@ odoo.define('hr_timesheet.Timer', function (require) { return new Timer(hours, Math.round(minutes), 0); } + /** + * Create timer + * @param {number} unit_amount + * @param {String} timer_start + * @param {String} serverTime + */ + static createTimer(unit_amount, timer_start, serverTime) { + const timer = this.convertFloatToTime(unit_amount); + + timer.addTime( + moment.utc( + moment.utc(serverTime) + .diff(moment.utc(timer_start)) + ).format("HH:mm:ss") + ); + + return timer; + } + addHours(hours) { this.hours += hours; } diff --git a/addons/hr_timesheet/static/src/js/timer.js b/addons/hr_timesheet/static/src/js/timer.js index e7330755822..f1ef8edd53e 100644 --- a/addons/hr_timesheet/static/src/js/timer.js +++ b/addons/hr_timesheet/static/src/js/timer.js @@ -3,6 +3,7 @@ odoo.define('hr_timesheet.timer', function (require) { var fieldRegistry = require('web.field_registry'); var AbstractField = require('web.AbstractField'); +var Timer = require('hr_timesheet.Timer'); var TimerFieldWidget = AbstractField.extend({ @@ -13,48 +14,47 @@ var TimerFieldWidget = AbstractField.extend({ isSet: function () { return true; }, - /** - * @private - */ - _getDuration: function (dateStart, datePause) { - if (datePause && dateStart) { - return moment(datePause).diff(moment(dateStart)); - } - if (dateStart) { - return moment().diff(moment(dateStart)); - } - else return 0; - }, /** * @override * @private */ _render: function () { this._startTimeCounter(); - }, /** * @override */ destroy: function () { this._super.apply(this, arguments); - clearTimeout(this.timer); + clearInterval(this.timer); }, /** * @private */ - _startTimeCounter: function () { - var self = this; - clearTimeout(this.timer); - if (self.record.data.timer_start) { - this.timer = setTimeout(function () { - self._startTimeCounter(); + _startTimeCounter: async function () { + if (this.record.data.timer_start) { + const serverTime = this.record.data.timer_pause || await this._getServerTime(); + this.time = Timer.createTimer(0, this.record.data.timer_start, serverTime); + this.$el.text(this.time.toString()); + this.timer = setInterval(() => { + if (this.record.data.timer_pause) { + clearInterval(this.timer); + } else { + this.time.addSecond(); + this.$el.text(this.time.toString()); + } }, 1000); - this.$el.text(moment.utc(self._getDuration(self.record.data.timer_start, self.record.data.timer_pause)).format("HH:mm:ss")); - } else if (!self.record.data.timer_pause){ - clearTimeout(this.timer); + } else if (!this.record.data.timer_pause){ + clearInterval(this.timer); } }, + _getServerTime: function () { + return this._rpc({ + model: 'account.analytic.line', + method: 'get_server_time', + args: [false] + }); + } }); fieldRegistry.add('timesheet_timer', TimerFieldWidget); diff --git a/addons/hr_timesheet/static/src/js/timesheet_uom.js b/addons/hr_timesheet/static/src/js/timesheet_uom.js index 3e9e192b8f1..9b74f686c4e 100644 --- a/addons/hr_timesheet/static/src/js/timesheet_uom.js +++ b/addons/hr_timesheet/static/src/js/timesheet_uom.js @@ -86,14 +86,19 @@ const FieldTimesheetTime = basicFields.FieldFloatTime.extend({ this.parseOptions.factor = session.timesheet_uom_factor; } }, - _render: function () { + _render: async function () { this._super.apply(this, arguments); // Check if the timer_start exists and it's not false // In other word, when user clicks on play button, this button // launches the "action_timer_start". if (this.recordData.timer_start) { - this.time = this._createTimer(this.recordData.unit_amount, this.recordData.timer_start); + const time = await this._rpc({ + model: this.model, + method: 'get_server_time', + args: [false] + }); + this.time = Timer.createTimer(this.recordData.unit_amount, this.recordData.timer_start, time); return this._startTimeCounter(); } else if (this.mode === "edit") { return this._renderEdit(); @@ -108,18 +113,6 @@ const FieldTimesheetTime = basicFields.FieldFloatTime.extend({ this._super.apply(this, arguments); clearTimeout(this.timer); }, - _createTimer: function (unit_amount, timer_start) { - const timer = Timer.convertFloatToTime(unit_amount); - - timer.addTime( - moment.utc( - moment() - .diff(moment(timer_start)) - ).format("HH:mm:ss") - ); - - return timer; - }, _startTimeCounter: function () { if (this.time) { this.timer = setInterval(() => {