[ADD]:Added Upstream patch for barcodes
This commit is contained in:
parent
f26524e7dd
commit
1617df3efc
@ -53,7 +53,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
|||||||
navigator.userAgent.match(/iPod/i) ||
|
navigator.userAgent.match(/iPod/i) ||
|
||||||
navigator.userAgent.match(/BlackBerry/i) ||
|
navigator.userAgent.match(/BlackBerry/i) ||
|
||||||
navigator.userAgent.match(/Windows Phone/i);
|
navigator.userAgent.match(/Windows Phone/i);
|
||||||
this.isChromeMobile = isMobile && window.chrome;
|
this.isChromeMobile = isMobile && navigator.userAgent.match(/Chrome/i);
|
||||||
|
|
||||||
// Creates an input who will receive the barcode scanner value.
|
// Creates an input who will receive the barcode scanner value.
|
||||||
if (this.isChromeMobile) {
|
if (this.isChromeMobile) {
|
||||||
@ -61,13 +61,17 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
|||||||
name: 'barcode',
|
name: 'barcode',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
css: {
|
css: {
|
||||||
'position': 'absolute',
|
'position': 'fixed',
|
||||||
'opacity': 0,
|
'top': '50%',
|
||||||
|
'transform': 'translateY(-50%)',
|
||||||
|
'z-index': '-1',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// Avoid to show autocomplete for a non appearing input
|
||||||
|
this.$barcodeInput.attr('autocomplete', 'off');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.__removeBarcodeField = _.debounce(this._removeBarcodeField, this.inputTimeOut);
|
this.__blurBarcodeInput = _.debounce(this._blurBarcodeInput, this.inputTimeOut);
|
||||||
},
|
},
|
||||||
|
|
||||||
handle_buffered_keys: function() {
|
handle_buffered_keys: function() {
|
||||||
@ -230,7 +234,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
|||||||
this.max_time_between_keys_in_ms);
|
this.max_time_between_keys_in_ms);
|
||||||
}
|
}
|
||||||
// if the barcode input doesn't receive keydown for a while, remove it.
|
// if the barcode input doesn't receive keydown for a while, remove it.
|
||||||
this.__removeBarcodeField();
|
this.__blurBarcodeInput();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -245,21 +249,22 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
|||||||
var barcodeValue = this.$barcodeInput.val();
|
var barcodeValue = this.$barcodeInput.val();
|
||||||
if (barcodeValue.match(this.regexp)) {
|
if (barcodeValue.match(this.regexp)) {
|
||||||
core.bus.trigger('barcode_scanned', barcodeValue, $(e.target).parent()[0]);
|
core.bus.trigger('barcode_scanned', barcodeValue, $(e.target).parent()[0]);
|
||||||
this.$barcodeInput.val('');
|
this._blurBarcodeInput();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the temporary input created to store the barcode value.
|
* Removes the value and focus from the barcode input.
|
||||||
* If nothing happens, this input will be removed, so the focus will be lost
|
* If nothing happens, the focus will be lost and
|
||||||
* and the virtual keyboard on mobile devices will be closed.
|
* the virtual keyboard on mobile devices will be closed.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_removeBarcodeField: function () {
|
_blurBarcodeInput: function () {
|
||||||
if (this.$barcodeInput) {
|
if (this.$barcodeInput) {
|
||||||
// Reset the value and remove from the DOM.
|
// Close the virtual keyboard on mobile browsers
|
||||||
this.$barcodeInput.val('').remove();
|
// FIXME: actually we can't prevent keyboard from opening
|
||||||
|
this.$barcodeInput.val('').blur();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -146,10 +146,10 @@ FormController.include({
|
|||||||
* @param {Object} activeBarcode: options sent by the field who use barcode features
|
* @param {Object} activeBarcode: options sent by the field who use barcode features
|
||||||
* @returns {Deferred}
|
* @returns {Deferred}
|
||||||
*/
|
*/
|
||||||
_barcodeSelectedCandidate: function (candidate, record, barcode, activeBarcode) {
|
_barcodeSelectedCandidate: function (candidate, record, barcode, activeBarcode, quantity) {
|
||||||
var changes = {};
|
var changes = {};
|
||||||
var candidateChanges = {};
|
var candidateChanges = {};
|
||||||
candidateChanges[activeBarcode.quantity] = candidate.data[activeBarcode.quantity] + 1;
|
candidateChanges[activeBarcode.quantity] = quantity ? quantity : candidate.data[activeBarcode.quantity] + 1;
|
||||||
changes[activeBarcode.fieldName] = {
|
changes[activeBarcode.fieldName] = {
|
||||||
operation: 'UPDATE',
|
operation: 'UPDATE',
|
||||||
id: candidate.id,
|
id: candidate.id,
|
||||||
@ -283,6 +283,9 @@ FormController.include({
|
|||||||
function (reserved) {return barcode.indexOf(reserved) === 0;});
|
function (reserved) {return barcode.indexOf(reserved) === 0;});
|
||||||
var hasCommand = false;
|
var hasCommand = false;
|
||||||
var defs = [];
|
var defs = [];
|
||||||
|
if (! $.contains(target, self.el)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (var k in self.activeBarcode) {
|
for (var k in self.activeBarcode) {
|
||||||
var activeBarcode = self.activeBarcode[k];
|
var activeBarcode = self.activeBarcode[k];
|
||||||
// Handle the case where there are several barcode widgets on the same page. Since the
|
// Handle the case where there are several barcode widgets on the same page. Since the
|
||||||
@ -306,6 +309,8 @@ FormController.include({
|
|||||||
}
|
}
|
||||||
return self.alive($.when.apply($, defs)).then(function () {
|
return self.alive($.when.apply($, defs)).then(function () {
|
||||||
if (!prefixed) {
|
if (!prefixed) {
|
||||||
|
// remember the barcode scanned for the quantity listener
|
||||||
|
self.current_barcode = barcode;
|
||||||
// redraw the view if we scanned a real barcode (required if
|
// redraw the view if we scanned a real barcode (required if
|
||||||
// we manually apply the change in JS, e.g. incrementing the
|
// we manually apply the change in JS, e.g. incrementing the
|
||||||
// quantity)
|
// quantity)
|
||||||
@ -321,6 +326,9 @@ FormController.include({
|
|||||||
_quantityListener: function (event) {
|
_quantityListener: function (event) {
|
||||||
var character = String.fromCharCode(event.which);
|
var character = String.fromCharCode(event.which);
|
||||||
|
|
||||||
|
if (! $.contains(event.target, this.el)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// only catch the event if we're not focused in
|
// only catch the event if we're not focused in
|
||||||
// another field and it's a number
|
// another field and it's a number
|
||||||
if (!$(event.target).is('body, .modal') || !/[0-9]/.test(character)) {
|
if (!$(event.target).is('body, .modal') || !/[0-9]/.test(character)) {
|
||||||
@ -355,9 +363,10 @@ FormController.include({
|
|||||||
title: _t('Set quantity'),
|
title: _t('Set quantity'),
|
||||||
buttons: [{text: _t('Select'), classes: 'btn-primary', close: true, click: function () {
|
buttons: [{text: _t('Select'), classes: 'btn-primary', close: true, click: function () {
|
||||||
var new_qty = this.$content.find('.o_set_qty_input').val();
|
var new_qty = this.$content.find('.o_set_qty_input').val();
|
||||||
var values = {};
|
var record = self.model.get(self.handle);
|
||||||
values[activeBarcode.quantity] = parseFloat(new_qty);
|
return self._barcodeSelectedCandidate(activeBarcode.candidate, record,
|
||||||
return self.model.notifyChanges(activeBarcode.candidate.id, values).then(function () {
|
self.current_barcode, activeBarcode, parseFloat(new_qty))
|
||||||
|
.then(function () {
|
||||||
self.update({}, {reload: false});
|
self.update({}, {reload: false});
|
||||||
});
|
});
|
||||||
}}, {text: _t('Discard'), close: true}],
|
}}, {text: _t('Discard'), close: true}],
|
||||||
|
@ -18,6 +18,9 @@ var BarcodeParser = Class.extend({
|
|||||||
// only when those data have been loaded
|
// only when those data have been loaded
|
||||||
load: function(){
|
load: function(){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
if (!this.nomenclature_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var id = this.nomenclature_id[0];
|
var id = this.nomenclature_id[0];
|
||||||
rpc.query({
|
rpc.query({
|
||||||
model: 'barcode.nomenclature',
|
model: 'barcode.nomenclature',
|
||||||
|
@ -404,4 +404,136 @@ QUnit.test('specification of widget barcode_handler', function (assert) {
|
|||||||
barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = delay;
|
barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = delay;
|
||||||
delete fieldRegistry.map.test_barcode_handler;
|
delete fieldRegistry.map.test_barcode_handler;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QUnit.test('specification of widget barcode_handler with keypress and notifyChange', function (assert) {
|
||||||
|
assert.expect(6);
|
||||||
|
var done = assert.async();
|
||||||
|
|
||||||
|
var delay = barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms;
|
||||||
|
barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = 0;
|
||||||
|
|
||||||
|
this.data.order.onchanges = {
|
||||||
|
_barcode_scanned: function () {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define a specific barcode_handler widget for this test case
|
||||||
|
var TestBarcodeHandler = AbstractField.extend({
|
||||||
|
init: function () {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
|
this.trigger_up('activeBarcode', {
|
||||||
|
name: 'test',
|
||||||
|
fieldName: 'line_ids',
|
||||||
|
notifyChange: false,
|
||||||
|
setQuantityWithKeypress: true,
|
||||||
|
quantity: 'quantity',
|
||||||
|
commands: {
|
||||||
|
barcode: '_barcodeAddX2MQuantity',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
fieldRegistry.add('test_barcode_handler', TestBarcodeHandler);
|
||||||
|
|
||||||
|
var form = createView({
|
||||||
|
View: FormView,
|
||||||
|
model: 'order',
|
||||||
|
data: this.data,
|
||||||
|
arch: '<form>' +
|
||||||
|
'<field name="_barcode_scanned" widget="test_barcode_handler"/>' +
|
||||||
|
'<field name="line_ids">' +
|
||||||
|
'<tree>' +
|
||||||
|
'<field name="product_id"/>' +
|
||||||
|
'<field name="product_barcode" invisible="1"/>' +
|
||||||
|
'<field name="quantity"/>' +
|
||||||
|
'</tree>' +
|
||||||
|
'</field>' +
|
||||||
|
'</form>',
|
||||||
|
mockRPC: function (route, args) {
|
||||||
|
assert.step(args.method);
|
||||||
|
return this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
|
res_id: 1,
|
||||||
|
viewOptions: {
|
||||||
|
mode: 'edit',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
_.each(['1','2','3','4','5','6','7','8','9','0','Enter'], triggerKeypressEvent);
|
||||||
|
// Quantity listener should open a dialog.
|
||||||
|
triggerKeypressEvent('5');
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
var keycode = $.ui.keyCode.ENTER;
|
||||||
|
|
||||||
|
assert.strictEqual($('.modal .modal-body').length, 1, 'should open a modal with a quantity as input');
|
||||||
|
assert.strictEqual($('.modal .modal-body .o_set_qty_input').val(), '5', 'the quantity by default in the modal shoud be 5');
|
||||||
|
|
||||||
|
$('.modal .modal-body .o_set_qty_input').val('7');
|
||||||
|
|
||||||
|
$('.modal .modal-body .o_set_qty_input').trigger($.Event('keypress', {which: keycode, keyCode: keycode}));
|
||||||
|
assert.strictEqual(form.$('.o_data_row .o_data_cell:nth(1)').text(), '7',
|
||||||
|
"quantity checked should be 7");
|
||||||
|
|
||||||
|
assert.verifySteps(['read', 'read']);
|
||||||
|
|
||||||
|
form.destroy();
|
||||||
|
barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = delay;
|
||||||
|
delete fieldRegistry.map.test_barcode_handler;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
QUnit.test('barcode_scanned only trigger error for active view', function (assert) {
|
||||||
|
assert.expect(2);
|
||||||
|
|
||||||
|
this.data.order_line.fields._barcode_scanned = {string: 'Barcode scanned', type: 'char'};
|
||||||
|
|
||||||
|
var form = createView({
|
||||||
|
View: FormView,
|
||||||
|
model: 'order',
|
||||||
|
data: this.data,
|
||||||
|
arch: '<form>' +
|
||||||
|
'<field name="_barcode_scanned" widget="barcode_handler"/>' +
|
||||||
|
'<field name="line_ids">' +
|
||||||
|
'<tree>' +
|
||||||
|
'<field name="product_id"/>' +
|
||||||
|
'<field name="product_barcode" invisible="1"/>' +
|
||||||
|
'<field name="quantity"/>' +
|
||||||
|
'</tree>' +
|
||||||
|
'</field>' +
|
||||||
|
'</form>',
|
||||||
|
archs: {
|
||||||
|
"order_line,false,form":
|
||||||
|
'<form string="order line">' +
|
||||||
|
'<field name="_barcode_scanned" widget="barcode_handler"/>' +
|
||||||
|
'<field name="product_id"/>' +
|
||||||
|
'</form>',
|
||||||
|
},
|
||||||
|
res_id: 1,
|
||||||
|
intercepts: {
|
||||||
|
warning: function (event) {
|
||||||
|
assert.step(event.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
viewOptions: {
|
||||||
|
mode: 'edit',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
form.$('.o_data_row:first').click();
|
||||||
|
|
||||||
|
// We do not trigger on the body since modal and
|
||||||
|
// form view are both inside it.
|
||||||
|
function modalTriggerKeypressEvent(char) {
|
||||||
|
var keycode;
|
||||||
|
if (char === "Enter") {
|
||||||
|
keycode = $.ui.keyCode.ENTER;
|
||||||
|
} else {
|
||||||
|
keycode = char.charCodeAt(0);
|
||||||
|
}
|
||||||
|
return $('.modal').trigger($.Event('keypress', {which: keycode, keyCode: keycode}));
|
||||||
|
}
|
||||||
|
_.each(['O','-','B','T','N','.','c','a','n','c','e','l','Enter'], modalTriggerKeypressEvent);
|
||||||
|
assert.verifySteps(['warning'], "only one event should be triggered");
|
||||||
|
form.destroy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user