From 8019eacb4716befcc0affa4f8c9d554be2ec6655 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Thu, 24 Aug 2017 14:36:53 +0200 Subject: [PATCH] [FIX] barcodes: generate correct update command The barcode mechanism is optimized to (in certain conditions), directly increment the quantity of a numerical field inside an x2many, without performing any RPC, and then re-rendering the x2many to display the new value. Before this rev., it seemed to work fine, but when the view was saved, those changes of quantity were lost. This was because the changes weren't correctly notified to the model (the quantity field being inside an x2many, the correct update command for the x2many should be generated). --- .../static/src/js/barcode_form_view.js | 10 +- addons/barcodes/static/tests/barcode_tests.js | 106 +++++++++++++++++- 2 files changed, 111 insertions(+), 5 deletions(-) diff --git a/addons/barcodes/static/src/js/barcode_form_view.js b/addons/barcodes/static/src/js/barcode_form_view.js index c238df4da59..8f6a3b0a3e2 100644 --- a/addons/barcodes/static/src/js/barcode_form_view.js +++ b/addons/barcodes/static/src/js/barcode_form_view.js @@ -93,8 +93,14 @@ FormController.include({ */ _barcodeSelectedCandidate: function (candidate, record, barcode, activeBarcode) { var changes = {}; - changes[activeBarcode.quantity] = candidate.data[activeBarcode.quantity] + 1; - return this.model.notifyChanges(candidate.id, changes); + var candidateChanges = {}; + candidateChanges[activeBarcode.quantity] = candidate.data[activeBarcode.quantity] + 1; + changes[activeBarcode.fieldName] = { + operation: 'UPDATE', + id: candidate.id, + data: candidateChanges, + }; + return this.model.notifyChanges(this.handle, changes); }, /** * @private diff --git a/addons/barcodes/static/tests/barcode_tests.js b/addons/barcodes/static/tests/barcode_tests.js index cb999cee168..5f8af60911b 100644 --- a/addons/barcodes/static/tests/barcode_tests.js +++ b/addons/barcodes/static/tests/barcode_tests.js @@ -3,9 +3,11 @@ odoo.define('barcodes.tests', function (require) { var barcodeEvents = require('barcodes.BarcodeEvents'); -var testUtils = require('web.test_utils'); +var AbstractField = require('web.AbstractField'); +var fieldRegistry = require('web.field_registry'); var FormController = require('web.FormController'); var FormView = require('web.FormView'); +var testUtils = require('web.test_utils'); var createView = testUtils.createView; var triggerKeypressEvent = testUtils.triggerKeypressEvent; @@ -13,14 +15,35 @@ var triggerKeypressEvent = testUtils.triggerKeypressEvent; QUnit.module('Barcodes', { beforeEach: function () { this.data = { + order: { + fields: { + _barcode_scanned: {string: 'Barcode scanned', type: 'char'}, + line_ids: {string: 'Order lines', type: 'one2many', relation: 'order_line'}, + }, + records: [ + {id: 1, line_ids: [1, 2]}, + ], + }, + order_line: { + fields: { + product_id: {string: 'Product', type: 'many2one', relation: 'product'}, + product_barcode: {string: 'Product Barcode', type: 'char'}, + quantity: {string: 'Quantity', type: 'integer'}, + }, + records: [ + {id: 1, product_id: 1, quantity: 0, product_barcode: '1234567890'}, + {id: 2, product_id: 2, quantity: 0, product_barcode: '0987654321'}, + ], + }, product: { fields: { name: {string : "Product name", type: "char"}, int_field: {string : "Integer", type: "integer"}, + barcode: {string: "Barcode", type: "char"}, }, records: [ - {id: 1, name: "iPad Mini"}, - {id: 2, name: "Mouse, Optical"}, + {id: 1, name: "iPad Mini", barcode: '1234567890'}, + {id: 2, name: "Mouse, Optical", barcode: '0987654321'}, ], }, }; @@ -298,4 +321,81 @@ QUnit.test('widget barcode_handler', function (assert) { barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = delay; }); +QUnit.test('specification of widget barcode_handler', function (assert) { + assert.expect(5); + + var delay = barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms; + barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = 0; + + // 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', + quantity: 'quantity', + commands: { + barcode: '_barcodeAddX2MQuantity', + } + }); + }, + }); + var previousField = fieldRegistry.get('test_barcode_handler'); + fieldRegistry.add('test_barcode_handler', TestBarcodeHandler); + + var form = createView({ + View: FormView, + model: 'order', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '', + mockRPC: function (route, args) { + if (args.method === 'onchange') { + assert.notOK(true, "should not do any onchange RPC"); + } + if (args.method === 'write') { + assert.deepEqual(args.args[1].line_ids, [ + [1, 1, {quantity: 2}], [1, 2, {quantity: 1}], + ], "should have generated the correct commands"); + } + return this._super.apply(this, arguments); + }, + res_id: 1, + viewOptions: { + mode: 'edit', + }, + }); + + assert.strictEqual(form.$('.o_data_row').length, 2, + "one2many should contain 2 rows"); + + // scan twice product 1 + _.each(['1','2','3','4','5','6','7','8','9','0','Enter'], triggerKeypressEvent); + assert.strictEqual(form.$('.o_data_row:first .o_data_cell:nth(1)').text(), '1', + "quantity of line one should have been incremented"); + _.each(['1','2','3','4','5','6','7','8','9','0','Enter'], triggerKeypressEvent); + assert.strictEqual(form.$('.o_data_row:first .o_data_cell:nth(1)').text(), '2', + "quantity of line one should have been incremented"); + + // scan once product 2 + _.each(['0','9','8','7','6','5','4','3','2','1','Enter'], triggerKeypressEvent); + assert.strictEqual(form.$('.o_data_row:nth(1) .o_data_cell:nth(1)').text(), '1', + "quantity of line one should have been incremented"); + + form.$buttons.find('.o_form_button_save').click(); + + form.destroy(); + barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = delay; + fieldRegistry.add('test_barcode_handler', previousField); +}); });