[FIX] web: reload right record when editing a many2one inside an x2many

Before this revision, editing a many2one inside an x2many field did not
cause an update of the x2many field upon saving. This is due to the fact
that a field on a screen was deemed affected by a record change only if
its value or a directly related record has been updated.

This present revision looks for changes recursively, thereby including
the case where an x2many field contains a many2one.

The bug appeared for example in Manufacturing, when editing the product
name of a BOM line.
This commit is contained in:
Khoi Nguyen
2017-08-04 11:31:58 +02:00
parent d19671f0d0
commit c300e5ede7
2 changed files with 65 additions and 7 deletions
@@ -217,7 +217,7 @@ var FormController = BasicController.extend({
*
* @private
* @override method from field manager mixin
* @param {string} id
* @param {string} id - id of the previously changed record
* @returns {Deferred}
*/
_confirmSave: function (id) {
@@ -228,15 +228,21 @@ var FormController = BasicController.extend({
return this._setMode('readonly');
}
} else {
// a subrecord changed, so update the corresponding relational field
// A subrecord has changed, so update the corresponding relational field
// i.e. the one whose value is a record with the given id or a list
// having a record with the given id in its data
var record = this.model.get(this.handle);
var fieldsChanged = _.findKey(record.data, function (d) {
return _.isObject(d) &&
(d.id === id || _.findWhere(d.data, {id: id}));
});
return this.renderer.confirmChange(record, record.id, [fieldsChanged]);
// Callback function which returns true
// if a value recursively contains a record with the given id.
// This will be used to determine the list of fields to reload.
var containsChangedRecord = function (value) {
return _.isObject(value) &&
(value.id === id || _.find(value.data, containsChangedRecord));
};
var changedFields = _.findKey(record.data, containsChangedRecord);
return this.renderer.confirmChange(record, record.id, [changedFields]);
}
},
/**
@@ -1418,6 +1418,58 @@ QUnit.module('relational_fields', {
form.destroy();
});
QUnit.test('updating a many2one from a many2many', function (assert) {
assert.expect(4);
this.data.turtle.records[1].turtle_trululu = 1;
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form string="Partners">' +
'<group>' +
'<field name="turtles">' +
'<tree editable="bottom">' +
'<field name="display_name"/>' +
'<field name="turtle_trululu"/>' +
'</tree>' +
'</field>' +
'</group>' +
'</form>',
res_id: 1,
archs: {
'partner,false,form': '<form string="Trululu"><field name="display_name"/></form>',
},
mockRPC: function (route, args) {
if (args.method === 'get_formview_id') {
assert.deepEqual(args.args[0], [1], "should call get_formview_id with correct id");
return $.when(false);
}
return this._super(route, args);
},
});
// Opening the modal
form.$buttons.find('.o_form_button_edit').click();
form.$('.o_data_row td:contains(first record)').click();
form.$('.o_external_button').click();
assert.strictEqual($('.modal').length, 1,
"should have one modal in body");
// Changing the 'trululu' value
$('.modal input[name="display_name"]').val('test').trigger('input');
$('.modal button.btn-primary').click();
// Test whether the value has changed
assert.strictEqual($('.modal').length, 0,
"the modal should be closed");
assert.equal(form.$('.o_data_cell:contains(test)').text(), 'test',
"the partner name should have been updated to 'test'");
form.destroy();
});
QUnit.module('FieldOne2Many');
QUnit.test('one2many basic properties', function (assert) {