From 1617df3efca95344f150b939e4c48358a69111f2 Mon Sep 17 00:00:00 2001 From: sheetalPatil Date: Mon, 9 Jul 2018 18:58:22 +0530 Subject: [PATCH] [ADD]:Added Upstream patch for barcodes --- .../barcodes/static/src/js/barcode_events.js | 29 ++-- .../static/src/js/barcode_form_view.js | 19 ++- .../barcodes/static/src/js/barcode_parser.js | 3 + addons/barcodes/static/tests/barcode_tests.js | 132 ++++++++++++++++++ 4 files changed, 166 insertions(+), 17 deletions(-) diff --git a/addons/barcodes/static/src/js/barcode_events.js b/addons/barcodes/static/src/js/barcode_events.js index c9e9b855..9028d657 100644 --- a/addons/barcodes/static/src/js/barcode_events.js +++ b/addons/barcodes/static/src/js/barcode_events.js @@ -53,7 +53,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, { navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/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. if (this.isChromeMobile) { @@ -61,13 +61,17 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, { name: 'barcode', type: 'text', css: { - 'position': 'absolute', - 'opacity': 0, + 'position': 'fixed', + '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() { @@ -230,7 +234,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, { this.max_time_between_keys_in_ms); } // 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(); if (barcodeValue.match(this.regexp)) { 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. - * If nothing happens, this input will be removed, so the focus will be lost - * and the virtual keyboard on mobile devices will be closed. + * Removes the value and focus from the barcode input. + * If nothing happens, the focus will be lost and + * the virtual keyboard on mobile devices will be closed. * * @private */ - _removeBarcodeField: function () { + _blurBarcodeInput: function () { if (this.$barcodeInput) { - // Reset the value and remove from the DOM. - this.$barcodeInput.val('').remove(); + // Close the virtual keyboard on mobile browsers + // FIXME: actually we can't prevent keyboard from opening + this.$barcodeInput.val('').blur(); } }, diff --git a/addons/barcodes/static/src/js/barcode_form_view.js b/addons/barcodes/static/src/js/barcode_form_view.js index a765d5ee..a70b6cd1 100644 --- a/addons/barcodes/static/src/js/barcode_form_view.js +++ b/addons/barcodes/static/src/js/barcode_form_view.js @@ -146,10 +146,10 @@ FormController.include({ * @param {Object} activeBarcode: options sent by the field who use barcode features * @returns {Deferred} */ - _barcodeSelectedCandidate: function (candidate, record, barcode, activeBarcode) { + _barcodeSelectedCandidate: function (candidate, record, barcode, activeBarcode, quantity) { var changes = {}; var candidateChanges = {}; - candidateChanges[activeBarcode.quantity] = candidate.data[activeBarcode.quantity] + 1; + candidateChanges[activeBarcode.quantity] = quantity ? quantity : candidate.data[activeBarcode.quantity] + 1; changes[activeBarcode.fieldName] = { operation: 'UPDATE', id: candidate.id, @@ -283,6 +283,9 @@ FormController.include({ function (reserved) {return barcode.indexOf(reserved) === 0;}); var hasCommand = false; var defs = []; + if (! $.contains(target, self.el)) { + return; + } for (var k in self.activeBarcode) { var activeBarcode = self.activeBarcode[k]; // 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 () { 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 // we manually apply the change in JS, e.g. incrementing the // quantity) @@ -321,6 +326,9 @@ FormController.include({ _quantityListener: function (event) { var character = String.fromCharCode(event.which); + if (! $.contains(event.target, this.el)) { + return; + } // only catch the event if we're not focused in // another field and it's a number if (!$(event.target).is('body, .modal') || !/[0-9]/.test(character)) { @@ -355,9 +363,10 @@ FormController.include({ title: _t('Set quantity'), buttons: [{text: _t('Select'), classes: 'btn-primary', close: true, click: function () { var new_qty = this.$content.find('.o_set_qty_input').val(); - var values = {}; - values[activeBarcode.quantity] = parseFloat(new_qty); - return self.model.notifyChanges(activeBarcode.candidate.id, values).then(function () { + var record = self.model.get(self.handle); + return self._barcodeSelectedCandidate(activeBarcode.candidate, record, + self.current_barcode, activeBarcode, parseFloat(new_qty)) + .then(function () { self.update({}, {reload: false}); }); }}, {text: _t('Discard'), close: true}], diff --git a/addons/barcodes/static/src/js/barcode_parser.js b/addons/barcodes/static/src/js/barcode_parser.js index 8ece7fe9..2e83a9c8 100644 --- a/addons/barcodes/static/src/js/barcode_parser.js +++ b/addons/barcodes/static/src/js/barcode_parser.js @@ -18,6 +18,9 @@ var BarcodeParser = Class.extend({ // only when those data have been loaded load: function(){ var self = this; + if (!this.nomenclature_id) { + return; + } var id = this.nomenclature_id[0]; rpc.query({ model: 'barcode.nomenclature', diff --git a/addons/barcodes/static/tests/barcode_tests.js b/addons/barcodes/static/tests/barcode_tests.js index bb4f3f6e..7fb5c683 100644 --- a/addons/barcodes/static/tests/barcode_tests.js +++ b/addons/barcodes/static/tests/barcode_tests.js @@ -404,4 +404,136 @@ QUnit.test('specification of widget barcode_handler', function (assert) { barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = delay; 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: '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '', + 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: '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '', + archs: { + "order_line,false,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(); +}); });