[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.
This commit is contained in:
Xavier Bol (xbo)
2019-12-19 10:20:27 +01:00
committed by Yannick Tivisse
parent 15e41f59c7
commit 2d3a44e6bd
4 changed files with 62 additions and 37 deletions
@@ -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()
@@ -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;
}
+23 -23
View File
@@ -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);
@@ -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(() => {