[FIX] web: m2o updates its value after reload

Changes the behaviour of many2ones when their value is changed via a form dialog.

Before this commit, when editing a m2o with a form dialog opened by an external button,
the field triggered an onchange with its old value before reloading its widget.
This caused the edition in list views to display outdated information when
saving multiple records.

Now, the reload is executed first, then the onchange occurs so that the value is
the newly updated one.

Part of task 2078807

closes odoo/odoo#37576

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Julien Mougenot
2019-10-07 11:22:04 +00:00
parent 0f412d56d6
commit da2b247146
4 changed files with 56 additions and 5 deletions
@@ -726,8 +726,13 @@ var FieldMany2One = AbstractField.extend({
readonly: !self.can_write,
on_saved: function (record, changed) {
if (changed) {
self._setValue(self.value.data, {forceChange: true}).then(function() {
self.trigger_up('reload', {db_id: self.value.id});
const _setValue = self._setValue.bind(self, self.value.data, {
forceChange: true,
});
self.trigger_up('reload', {
db_id: self.value.id,
onSuccess: _setValue,
onFailure: _setValue,
});
}
},
@@ -705,21 +705,25 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* re-render (reload the whole form by default)
* @param {string[]} [ev.data.fieldNames] list of the record's fields to
* reload
* @param {Function} [ev.data.onSuccess] callback executed after reload is resolved
* @param {Function} [ev.data.onFailure] callback executed when reload is rejected
*/
_onReload: function (ev) {
ev.stopPropagation(); // prevent other controllers from handling this request
var data = ev && ev.data || {};
var handle = data.db_id;
var prom;
if (handle) {
// reload the relational field given its db_id
this.model.reload(handle).then(this._confirmSave.bind(this, handle));
prom = this.model.reload(handle).then(this._confirmSave.bind(this, handle));
} else {
// no db_id given, so reload the main record
this.reload({
prom = this.reload({
fieldNames: data.fieldNames,
keepChanges: data.keepChanges || false,
});
}
prom.then(ev.data.onSuccess).guardedCatch(ev.data.onFailure);
},
/**
* Resequence records in the given order.
@@ -557,7 +557,7 @@ QUnit.module('fields', {}, function () {
// save the modal and make sure an onchange is triggered
await testUtils.dom.click($('.modal .modal-footer .btn-primary').first());
assert.verifySteps(['read', 'get_formview_id', 'load_views', 'read', 'write', 'onchange', 'read']);
assert.verifySteps(['read', 'get_formview_id', 'load_views', 'read', 'write', 'read', 'onchange']);
// save the main record, and check that no extra rpcs are done (record
// is not dirty, only a related record was modified)
@@ -6074,6 +6074,48 @@ QUnit.module('Views', {
list.destroy();
});
QUnit.test('editable list: edit many2one from external link', async function (assert) {
assert.expect(2);
const list = await createView({
arch: `
<tree editable="top" multi_edit="1">
<field name="m2o"/>
</tree>`,
archs: {
'bar,false,form': '<form string="Bar"><field name="display_name"/></form>',
},
data: this.data,
mockRPC: function (route, args) {
if (args.method === 'get_formview_id') {
return Promise.resolve(false);
}
return this._super(route, args);
},
model: 'foo',
View: ListView,
});
await testUtils.dom.click(list.$('thead .o_list_record_selector:first input'));
await testUtils.dom.click(list.$('.o_data_row:first .o_data_cell:eq(0)'));
await testUtils.dom.click(list.$('.o_external_button:first'));
// Change the M2O value in the Form dialog
await testUtils.fields.editInput($('.modal input:first'), "OOF");
await testUtils.dom.click($('.modal .btn-primary'));
assert.strictEqual($('.modal .o_field_widget[name=m2o]').text(), "OOF",
"Value of the m2o should be updated in the confirmation dialog");
// Close the confirmation dialog
await testUtils.dom.click($('.modal .btn-primary'));
assert.strictEqual(list.$('.o_data_cell:first').text(), "OOF",
"Value of the m2o should be updated in the list");
list.destroy();
});
QUnit.test('list grouped by date:month', async function (assert) {
assert.expect(1);