[FIX] hr_attendance : kiosk mode multi scanning
- Scan a barcode for employee 1 in kiosk mode - At greetings message, scan a barcode for employee 2 2 attendance entries are created for employee 2 instead of 1. When scanning the barcode for employee 2, the event listener `_onBarcodeScanned` is still active on `KioskMode`. Therefore, the RPC call to `attendance_scan` is performed twice. We deactivate the event listener after scanning, and reactivate on `KioskMode` only if there is an issue. This is sufficient since the call to `do_action` in `GreetingMessage` will create another instance of the client action. In `GreetingMessage`, we add back the redirection to `KioskMode`. Co-authored-by: Nicolas Martinelli <nim@odoo.com> Linked to Task ID 1878251 opw-1878632 opw-1888402 closes odoo/odoo#28150
This commit is contained in:
committed by
Nicolas Martinelli
parent
edb648f6a1
commit
f20cd3db75
@@ -89,6 +89,7 @@ class HrEmployee(models.Model):
|
||||
action_message = self.env.ref('hr_attendance.hr_attendance_action_greeting_message').read()[0]
|
||||
action_message['previous_attendance_change_date'] = self.last_attendance_id and (self.last_attendance_id.check_out or self.last_attendance_id.check_in) or False
|
||||
action_message['employee_name'] = self.name
|
||||
action_message['barcode'] = self.barcode
|
||||
action_message['next_action'] = next_action
|
||||
|
||||
if self.user_id:
|
||||
|
||||
@@ -51,6 +51,7 @@ var GreetingMessage = Widget.extend({
|
||||
this.attendance.check_in_time = this.attendance.check_in && this.attendance.check_in.format(this.format_time);
|
||||
this.attendance.check_out_time = this.attendance.check_out && this.attendance.check_out.format(this.format_time);
|
||||
this.employee_name = action.employee_name;
|
||||
this.attendanceBarcode = action.barcode;
|
||||
},
|
||||
|
||||
start: function() {
|
||||
@@ -136,21 +137,27 @@ var GreetingMessage = Widget.extend({
|
||||
|
||||
_onBarcodeScanned: function(barcode) {
|
||||
var self = this;
|
||||
if (this.return_to_main_menu) { // in case of multiple scans in the greeting message view, delete the timer, a new one will be created.
|
||||
clearTimeout(this.return_to_main_menu);
|
||||
if (this.attendanceBarcode !== barcode){
|
||||
if (this.return_to_main_menu) { // in case of multiple scans in the greeting message view, delete the timer, a new one will be created.
|
||||
clearTimeout(this.return_to_main_menu);
|
||||
}
|
||||
core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
|
||||
this._rpc({
|
||||
model: 'hr.employee',
|
||||
method: 'attendance_scan',
|
||||
args: [barcode, ],
|
||||
})
|
||||
.then(function (result) {
|
||||
if (result.action) {
|
||||
self.do_action(result.action);
|
||||
} else if (result.warning) {
|
||||
self.do_warn(result.warning);
|
||||
setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
|
||||
}
|
||||
}, function () {
|
||||
setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
|
||||
});
|
||||
}
|
||||
this._rpc({
|
||||
model: 'hr.employee',
|
||||
method: 'attendance_scan',
|
||||
args: [barcode, ],
|
||||
})
|
||||
.then(function (result) {
|
||||
if (result.action) {
|
||||
self.do_action(result.action);
|
||||
} else if (result.warning) {
|
||||
self.do_warn(result.warning);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
|
||||
@@ -35,6 +35,7 @@ var KioskMode = Widget.extend({
|
||||
|
||||
_onBarcodeScanned: function(barcode) {
|
||||
var self = this;
|
||||
core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
|
||||
this._rpc({
|
||||
model: 'hr.employee',
|
||||
method: 'attendance_scan',
|
||||
@@ -45,7 +46,10 @@ var KioskMode = Widget.extend({
|
||||
self.do_action(result.action);
|
||||
} else if (result.warning) {
|
||||
self.do_warn(result.warning);
|
||||
core.bus.on('barcode_scanned', self, self._onBarcodeScanned);
|
||||
}
|
||||
}, function () {
|
||||
core.bus.on('barcode_scanned', self, self._onBarcodeScanned);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -2,8 +2,11 @@ odoo.define('hr_attendance.tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var testUtils = require('web.test_utils');
|
||||
var core = require('web.core');
|
||||
|
||||
var MyAttendances = require('hr_attendance.my_attendances');
|
||||
var KioskMode = require('hr_attendance.kiosk_mode');
|
||||
var GreetingMessage = require('hr_attendance.greeting_message');
|
||||
|
||||
|
||||
QUnit.module('HR Attendance', {
|
||||
@@ -19,12 +22,30 @@ QUnit.module('HR Attendance', {
|
||||
default: 1,
|
||||
},
|
||||
user_id: {string: 'user ID', type: 'integer'},
|
||||
barcode: {string:'barcode', type: 'integer'},
|
||||
},
|
||||
records: [{
|
||||
id: 1,
|
||||
name: "Employee A",
|
||||
attendance_state: 1,
|
||||
user_id: 1,
|
||||
barcode: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Employee B",
|
||||
attendance_state: 'checked_out',
|
||||
user_id: 2,
|
||||
barcode: 2,
|
||||
}],
|
||||
},
|
||||
'res.company': {
|
||||
fields: {
|
||||
name: {string: 'Name', type: 'char'},
|
||||
},
|
||||
records: [{
|
||||
id: 1,
|
||||
name: "Company A",
|
||||
}],
|
||||
},
|
||||
};
|
||||
@@ -51,6 +72,112 @@ QUnit.module('HR Attendance', {
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Attendance Kiosk Mode Test', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var $target = $('#qunit-fixture');
|
||||
var self = this;
|
||||
var rpcCount = 0;
|
||||
var clientAction = new KioskMode(null);
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
data: this.data,
|
||||
session: {
|
||||
uid: 1,
|
||||
company_id: 1,
|
||||
},
|
||||
mockRPC: function(route, args) {
|
||||
if (args.method === 'attendance_scan' && args.model === 'hr.employee') {
|
||||
|
||||
rpcCount++;
|
||||
return $.when(self.data['hr.employee'].records[0]);
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
clientAction.appendTo($target);
|
||||
core.bus.trigger('barcode_scanned', 1);
|
||||
core.bus.trigger('barcode_scanned', 1);
|
||||
assert.strictEqual(rpcCount, 1, 'RPC call should have been done only once.');
|
||||
|
||||
core.bus.trigger('barcode_scanned', 2);
|
||||
assert.strictEqual(rpcCount, 1, 'RPC call should have been done only once.');
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Attendance Greeting Message Test', function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
var $target = $('#qunit-fixture');
|
||||
var self = this;
|
||||
var rpcCount = 0;
|
||||
|
||||
var clientActions = [];
|
||||
function createGreetingMessage (target, barcode){
|
||||
var action = {
|
||||
attendance: {
|
||||
check_in: "2018-09-20 13:41:13",
|
||||
employee_id: [barcode],
|
||||
},
|
||||
next_action: "hr_attendance.hr_attendance_action_kiosk_mode",
|
||||
barcode: barcode,
|
||||
}
|
||||
var clientAction = new GreetingMessage(null, action);
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
data: self.data,
|
||||
session: {
|
||||
uid: 1,
|
||||
company_id: 1,
|
||||
},
|
||||
mockRPC: function(route, args) {
|
||||
if (args.method === 'attendance_scan' && args.model === 'hr.employee') {
|
||||
rpcCount++;
|
||||
action.attendance.employee_id = [args.args[0], 'Employee'];
|
||||
/*
|
||||
if rpc have been made, a new instance is created to simulate the same behaviour
|
||||
as functional flow.
|
||||
*/
|
||||
createGreetingMessage (target, args.args[0]);
|
||||
return $.when({action: action});
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
clientAction.appendTo(target);
|
||||
|
||||
clientActions.push(clientAction);
|
||||
};
|
||||
|
||||
// init - mock coming from kiosk
|
||||
createGreetingMessage ($target, 1);
|
||||
assert.strictEqual(clientActions.length, 1, 'Number of clientAction must = 1.');
|
||||
|
||||
core.bus.trigger('barcode_scanned', 1);
|
||||
/*
|
||||
As action is given when instantiate GreetingMessage, we simulate that we come from the KioskMode
|
||||
So rescanning the same barcode won't lead to another RPC.
|
||||
*/
|
||||
assert.strictEqual(clientActions.length, 1, 'Number of clientActions must = 1.');
|
||||
assert.strictEqual(rpcCount, 0, 'RPC call should not have been done.');
|
||||
|
||||
core.bus.trigger('barcode_scanned', 2);
|
||||
assert.strictEqual(clientActions.length, 2, 'Number of clientActions must = 2.');
|
||||
assert.strictEqual(rpcCount, 1, 'RPC call should have been done only once.');
|
||||
core.bus.trigger('barcode_scanned', 2);
|
||||
assert.strictEqual(clientActions.length, 2, 'Number of clientActions must = 2.');
|
||||
assert.strictEqual(rpcCount, 1, 'RPC call should have been done only once.');
|
||||
|
||||
core.bus.trigger('barcode_scanned', 1);
|
||||
assert.strictEqual(clientActions.length, 3, 'Number of clientActions must = 3.');
|
||||
core.bus.trigger('barcode_scanned', 1);
|
||||
assert.strictEqual(clientActions.length, 3, 'Number of clientActions must = 3.');
|
||||
assert.strictEqual(rpcCount, 2, 'RPC call should have been done only twice.');
|
||||
|
||||
_.each(clientActions, function(clientAction) {
|
||||
clientAction.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user