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(() => {