diff --git a/addons/sale/static/src/js/product_configurator_widget.js b/addons/sale/static/src/js/product_configurator_widget.js
index 5aab1cc988f..599cc4790cf 100644
--- a/addons/sale/static/src/js/product_configurator_widget.js
+++ b/addons/sale/static/src/js/product_configurator_widget.js
@@ -116,7 +116,7 @@ var ProductConfiguratorWidget = relationalFields.FieldMany2One.extend({
*/
reset: async function (record, ev) {
await this._super(...arguments);
- if (ev.target === this) {
+ if (ev && ev.target === this) {
if (ev.data.changes && !ev.data.preventProductIdCheck && ev.data.changes.product_template_id) {
this._onTemplateChange(record.data.product_template_id.data.id, ev.data.dataPointID);
} else if (ev.data.changes && ev.data.changes.product_id) {
diff --git a/addons/sale/static/tests/product_configurator_tests.js b/addons/sale/static/tests/product_configurator_tests.js
new file mode 100644
index 00000000000..eaed84889cd
--- /dev/null
+++ b/addons/sale/static/tests/product_configurator_tests.js
@@ -0,0 +1,100 @@
+odoo.define('sale.product_configurator_tests', function (require) {
+ "use strict";
+
+ const FormView = require('web.FormView');
+ const testUtils = require('web.test_utils');
+
+ const createView = testUtils.createView;
+
+ QUnit.module('product_configurator', {
+ beforeEach: function () {
+ this.data = {
+ order: {
+ fields: {
+ line_ids: {
+ string: "Lines",
+ type: 'one2many',
+ relation: 'line',
+ relation_field: 'order_id'
+ },
+ },
+ records: [
+ {id: 1, line_ids: [1, 2]},
+ ],
+ },
+ line: {
+ fields: {
+ product_id: {
+ string: "Product",
+ type: 'many2one',
+ relation: 'product',
+ },
+ order_id: {
+ string: "Order",
+ type: 'many2one',
+ relation: 'order'
+ },
+ sequence: {
+ string: "Sequence",
+ type: 'number',
+ },
+ },
+ records: [
+ {id: 1, sequence: 4, product_id: 3, order_id: 1},
+ {id: 2, sequence: 14, product_id: 4, order_id: 1},
+ ]
+ },
+ product: {
+ fields: {
+ name: {
+ string: "Name",
+ type: 'char',
+ },
+ },
+ records: [
+ {id: 3, name: "Chair"},
+ {id: 4, name: "Table"},
+ ],
+ },
+ };
+ },
+ }, function () {
+ QUnit.test('drag and drop rows containing product_configurator many2one', async function (assert) {
+ assert.expect(4);
+
+ const form = await createView({
+ View: FormView,
+ model: 'order',
+ data: this.data,
+ arch: `
+
`,
+ archs: {
+ 'line,false,list': `
+
+
+
+ `,
+ },
+ res_id: 1,
+ viewOptions: {
+ mode: 'edit',
+ },
+ });
+
+ assert.containsN(form, '.o_data_row', 2);
+ assert.strictEqual(form.$('.o_data_row').text(), 'ChairTable');
+ assert.containsN(form, '.o_data_row .o_row_handle', 2);
+
+ // move first row below second
+ const $firstHandle = form.$('.o_data_row:nth(0) .o_row_handle');
+ const $secondHandle = form.$('.o_data_row:nth(1) .o_row_handle');
+ await testUtils.dom.dragAndDrop($firstHandle, $secondHandle);
+
+ assert.strictEqual(form.$('.o_data_row').text(), 'TableChair');
+
+ form.destroy();
+ });
+ });
+});
diff --git a/addons/sale/views/assets.xml b/addons/sale/views/assets.xml
index 1733dab1a50..e5fac59fb2e 100644
--- a/addons/sale/views/assets.xml
+++ b/addons/sale/views/assets.xml
@@ -31,6 +31,7 @@
+
diff --git a/addons/sale_product_configurator/static/src/js/product_configurator_widget.js b/addons/sale_product_configurator/static/src/js/product_configurator_widget.js
index 48f15bbe63e..7769a72fc90 100644
--- a/addons/sale_product_configurator/static/src/js/product_configurator_widget.js
+++ b/addons/sale_product_configurator/static/src/js/product_configurator_widget.js
@@ -34,7 +34,7 @@ ProductConfiguratorWidget.include({
* @private
*/
reset: function (record, ev) {
- if (ev.target === this) {
+ if (ev && ev.target === this) {
this.restoreProductTemplateId = this.recordData.product_template_id;
this.optionalProducts = (ev.data && ev.data.optionalProducts) || this.optionalProducts;
}
diff --git a/addons/sale_product_configurator/static/tests/product_configurator.test.js b/addons/sale_product_configurator/static/tests/product_configurator.test.js
index 757e2f52743..2d737820c43 100644
--- a/addons/sale_product_configurator/static/tests/product_configurator.test.js
+++ b/addons/sale_product_configurator/static/tests/product_configurator.test.js
@@ -82,7 +82,8 @@ QUnit.module('Product Configurator', {
type: 'one2many',
relation: 'product_custom_attribute_value'
},
- product_uom_qty: {type: 'integer'}
+ product_uom_qty: {type: 'integer'},
+ sequence: {type: 'integer'},
}
},
product_custom_attribute_value: {
@@ -136,7 +137,7 @@ QUnit.module('Product Configurator', {
}
};
}
-}, function (){
+}, function () {
QUnit.test('Select a non configurable product template and verify that the product_id is correctly set', async function (assert) {
assert.expect(2);
@@ -225,7 +226,7 @@ QUnit.module('Product Configurator', {
form.destroy();
});
- QUnit.test('Select a product in the list and check for template loading', async function (assert){
+ QUnit.test('Select a product in the list and check for template loading', async function (assert) {
assert.expect(1);
var product_configurator_form = await createView({
@@ -257,6 +258,52 @@ QUnit.module('Product Configurator', {
await testUtils.dom.click($("ul.ui-autocomplete li a:contains('Customizable Desk')").mouseenter());
product_configurator_form.destroy();
});
+
+ QUnit.test('drag and drop rows containing product_configurator many2one', async function (assert) {
+ assert.expect(4);
+
+ this.data.sale_order.records = [
+ { id: 1, sale_order_line: [1, 2] }
+ ];
+ this.data.sale_order_line.records = [
+ { id: 1, sequence: 5, product_id: 1 },
+ { id: 2, sequence: 15, product_id: 2 },
+ ];
+
+ const form = await createView({
+ View: FormView,
+ model: 'sale_order',
+ data: this.data,
+ arch: `
+ `,
+ archs: {
+ 'sale_order_line,false,list': `
+
+
+
+ `,
+ },
+ res_id: 1,
+ viewOptions: {
+ mode: 'edit',
+ },
+ });
+
+ assert.containsN(form, '.o_data_row', 2);
+ assert.strictEqual(form.$('.o_data_row').text(), 'Customizable Desk (1)Customizable Desk (2)');
+ assert.containsN(form, '.o_data_row .o_row_handle', 2);
+
+ // move first row below second
+ const $firstHandle = form.$('.o_data_row:nth(0) .o_row_handle');
+ const $secondHandle = form.$('.o_data_row:nth(1) .o_row_handle');
+ await testUtils.dom.dragAndDrop($firstHandle, $secondHandle);
+
+ assert.strictEqual(form.$('.o_data_row').text(), 'Customizable Desk (2)Customizable Desk (1)');
+
+ form.destroy();
+ });
});
});