[REF] barcodes: simplify 'O-CMD.' implementation
With this commit, we simplify the way barcodes prefixed by `O-CMD.` are handled, by simply executing a ui action whenever it happens. The code is much simpler, instead of having to add a widget=barcode_handler in a specific view. Note that it changes the behaviour: now, barcodes are available everywhere, instead of just a selection of form views. This seems more natural, since we consider that the barcode scanner is basically some kind of input device. Part-of: odoo/odoo#95892
This commit is contained in:
@@ -2,29 +2,88 @@
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { getVisibleElements } from "@web/core/utils/ui";
|
||||
import { MacroEngine } from "@web/core/macro";
|
||||
|
||||
export const barcodeAutoClick = {
|
||||
function clickOnButton(selector) {
|
||||
const button = document.body.querySelector(selector);
|
||||
if (button) {
|
||||
button.click();
|
||||
}
|
||||
}
|
||||
function updatePager(position) {
|
||||
const pager = document.body.querySelector("nav.o_pager");
|
||||
if (!pager || pager.innerText.includes("-")) {
|
||||
// we don't change pages if we are in a multi record view
|
||||
return;
|
||||
}
|
||||
let next;
|
||||
if (position === "first") {
|
||||
next = 1;
|
||||
} else {
|
||||
next = parseInt(pager.querySelector(".o_pager_limit").textContent, 10);
|
||||
}
|
||||
let current = parseInt(pager.innerText.split('/')[0], 10);
|
||||
if (current === next) {
|
||||
return;
|
||||
}
|
||||
const engine = new MacroEngine();
|
||||
engine.activate({
|
||||
name: "updating pager",
|
||||
timeout: 1000,
|
||||
interval: 0,
|
||||
steps: [
|
||||
{
|
||||
trigger: "span.o_pager_value",
|
||||
action: "click"
|
||||
},
|
||||
{
|
||||
trigger: "input.o_pager_value",
|
||||
action: "text",
|
||||
value: next
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
const COMMANDS = {
|
||||
"O-CMD.EDIT": () => clickOnButton(".o_form_button_edit"),
|
||||
"O-CMD.DISCARD": () => clickOnButton(".o_form_button_cancel"),
|
||||
"O-CMD.SAVE": () => clickOnButton(".o_form_button_save"),
|
||||
"O-CMD.PREV": () => clickOnButton(".o_pager_previous"),
|
||||
"O-CMD.NEXT": () => clickOnButton(".o_pager_next"),
|
||||
"O-CMD.PAGER-FIRST": () => updatePager("first"),
|
||||
"O-CMD.PAGER-LAST": () => updatePager("last"),
|
||||
};
|
||||
|
||||
export const barcodeGenericHandlers = {
|
||||
dependencies: ["ui", "barcode"],
|
||||
start(env, { ui, barcode }) {
|
||||
|
||||
barcode.bus.addEventListener("barcode_scanned", (ev) => {
|
||||
const barcode = ev.detail.barcode;
|
||||
if (!barcode.startsWith("O-BTN.")) {
|
||||
return;
|
||||
if (barcode.startsWith("O-BTN.")) {
|
||||
let targets = [];
|
||||
try {
|
||||
// the scanned barcode could be anything, and could crash the queryselectorall
|
||||
// function
|
||||
targets = getVisibleElements(ui.activeElement, `[barcode_trigger=${barcode.slice(6)}]`);
|
||||
} catch (_e) {
|
||||
console.warn(`Barcode '${barcode}' is not valid`);
|
||||
}
|
||||
for (let elem of targets) {
|
||||
elem.click();
|
||||
}
|
||||
}
|
||||
let targets = [];
|
||||
try {
|
||||
// the scanned barcode could be anything, and could crash the queryselectorall
|
||||
// function
|
||||
targets = getVisibleElements(ui.activeElement, `[barcode_trigger=${barcode.slice(6)}]`);
|
||||
} catch (_e) {
|
||||
console.warn(`Barcode '${barcode}' is not valid`)
|
||||
}
|
||||
for (let elem of targets) {
|
||||
elem.click();
|
||||
if (barcode.startsWith("O-CMD.")) {
|
||||
const fn = COMMANDS[barcode];
|
||||
if (fn) {
|
||||
fn();
|
||||
} else {
|
||||
console.warn(`Barcode '${barcode}' is not a valid command`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
registry.category("services").add("barcode_autoclick", barcodeAutoClick);
|
||||
registry.category("services").add("barcode_handlers", barcodeGenericHandlers);
|
||||
|
||||
@@ -25,13 +25,6 @@ FormController.include({
|
||||
this.activeBarcode = {
|
||||
form_view: {
|
||||
commands: {
|
||||
'O-CMD.EDIT': this._barcodeEdit.bind(this),
|
||||
'O-CMD.DISCARD': this._barcodeDiscard.bind(this),
|
||||
'O-CMD.SAVE': this._barcodeSave.bind(this),
|
||||
'O-CMD.PREV': this._barcodePagerPrevious.bind(this),
|
||||
'O-CMD.NEXT': this._barcodePagerNext.bind(this),
|
||||
'O-CMD.PAGER-FIRST': this._barcodePagerFirst.bind(this),
|
||||
'O-CMD.PAGER-LAST': this._barcodePagerLast.bind(this),
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -71,84 +64,6 @@ FormController.include({
|
||||
return this._barcodeWithoutCandidate(record, barcode, activeBarcode);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_barcodeDiscard: function () {
|
||||
return this.discardChanges();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_barcodeEdit: function () {
|
||||
return this._setMode('edit');
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_barcodePagerFirst: async function () {
|
||||
return this._updatePage(() => 1);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_barcodePagerLast: async function () {
|
||||
return this._updatePage((min, state) => state.count);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_barcodePagerNext: function () {
|
||||
return this._updatePage((min, state) => {
|
||||
min += 1;
|
||||
if (min > state.count) {
|
||||
min = 1;
|
||||
}
|
||||
return min;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_barcodePagerPrevious: function () {
|
||||
return this._updatePage((min, state) => {
|
||||
min -= 1;
|
||||
if (min < 1) {
|
||||
min = state.count;
|
||||
}
|
||||
return min;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Change the current minimum value of the pager using provided function.
|
||||
* This function will be given the current minimum and state and must return
|
||||
* the updated value.
|
||||
*
|
||||
* @private
|
||||
* @param {Function(currentMin: Number, state: Object)} updater
|
||||
*/
|
||||
_updatePage: async function (updater) {
|
||||
await this.mutex.exec(() => {});
|
||||
const state = this.model.get(this.handle, { raw: true });
|
||||
const pagingInfo = this._getPagingInfo(state);
|
||||
if (!pagingInfo) {
|
||||
return this.displayNotification({ message: _t('Pager unavailable'), type: 'danger' });
|
||||
}
|
||||
const currentMinimum = updater(pagingInfo.currentMinimum, state);
|
||||
const limit = pagingInfo.limit;
|
||||
const reloadParams = state.groupedBy && state.groupedBy.length ? {
|
||||
groupsLimit: limit,
|
||||
groupsOffset: currentMinimum - 1,
|
||||
} : {
|
||||
limit,
|
||||
offset: currentMinimum - 1,
|
||||
};
|
||||
await this.reload(reloadParams);
|
||||
// reset the scroll position to the top on page changed only
|
||||
if (state.limit === limit) {
|
||||
this.trigger_up('scrollTo', { top: 0 });
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Returns true iff the given barcode matches the given record (candidate).
|
||||
*
|
||||
@@ -161,12 +76,6 @@ FormController.include({
|
||||
_barcodeRecordFilter: function (candidate, barcode, activeBarcode) {
|
||||
return candidate.data.product_barcode === barcode;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_barcodeSave: function () {
|
||||
return this.saveRecord();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} candidate: record in the x2m
|
||||
|
||||
@@ -2,10 +2,11 @@ odoo.define('barcodes.tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
const {barcodeService} = require("@barcodes/barcode_service");
|
||||
const {barcodeAutoClick} = require("@barcodes/barcode_handlers");
|
||||
const {barcodeGenericHandlers} = require("@barcodes/barcode_handlers");
|
||||
const {barcodeRemapperService} = require("@barcodes/js/barcode_events");
|
||||
const { makeTestEnv } = require("@web/../tests/helpers/mock_env");
|
||||
const { registry } = require("@web/core/registry");
|
||||
const { mockTimeout } = require("@web/../tests/helpers/utils");
|
||||
|
||||
var AbstractField = require('web.AbstractField');
|
||||
var fieldRegistry = require('web.field_registry');
|
||||
@@ -40,7 +41,7 @@ QUnit.module('Barcodes', {
|
||||
before() {
|
||||
barcodeService.maxTimeBetweenKeysInMs = 0;
|
||||
registry.category("services").add("barcode", barcodeService, { force: true});
|
||||
registry.category("services").add("barcode_autoclick", barcodeAutoClick, { force: true});
|
||||
registry.category("services").add("barcode_autoclick", barcodeGenericHandlers, { force: true});
|
||||
// remove this one later
|
||||
registry.category("services").add("barcode_remapper", barcodeRemapperService);
|
||||
this.env = makeTestEnv();
|
||||
@@ -172,10 +173,12 @@ QUnit.test('edit, save and cancel buttons', async function (assert) {
|
||||
});
|
||||
|
||||
QUnit.test('pager buttons', async function (assert) {
|
||||
const mock = mockTimeout();
|
||||
assert.expect(5);
|
||||
|
||||
var form = await createView({
|
||||
View: FormView,
|
||||
debug: true,
|
||||
model: 'product',
|
||||
data: this.data,
|
||||
arch: '<form><field name="display_name"/></form>',
|
||||
@@ -197,11 +200,15 @@ QUnit.test('pager buttons', async function (assert) {
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'Large Cabinet');
|
||||
// O-CMD.PAGER-LAST
|
||||
simulateBarCode(["O","-","C","M","D",".","P","A","G","E","R","-","L","A","S","T","Enter"]);
|
||||
await testUtils.nextTick();
|
||||
// need to await 2 macro steps
|
||||
await mock.advanceTime(20);
|
||||
await mock.advanceTime(20);
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'Cabinet with Doors');
|
||||
// O-CMD.PAGER-FIRST
|
||||
simulateBarCode(["O","-","C","M","D",".","P","A","G","E","R","-","F","I","R","S","T","Enter"]);
|
||||
await testUtils.nextTick();
|
||||
// need to await 2 macro steps
|
||||
await mock.advanceTime(20);
|
||||
await mock.advanceTime(20);
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'Large Cabinet');
|
||||
|
||||
form.destroy();
|
||||
|
||||
Reference in New Issue
Block a user