[FIX] web: nested x2many with non inline views

Let's assume a form view with an x2many list, containing itself
an x2many field (no widget, so simply displaying the number of
records). When a record of the list is clicked, a form view
opens and displays the same sub x2many field, with widget
many2many_tags. Both list and form views of the x2many aren't
inline (thus have to be fetched on demand).

Before this commit, it crashed when the user clicked on a row
of the x2many list.

The bug has been introduced by a9cebd5a, which wrongly removed the
code handling this specific situation. At least, now we have a
test attesting that this code isn't useless.

Note that the diff isn't as scary as it looks like (we just added
an if/else, and thus indented the former code inside the else
clause).

closes odoo/odoo#48116

Signed-off-by: Géry Debongnie (ged) <ged@openerp.com>
This commit is contained in:
Aaron Bohy
2020-03-20 13:40:42 +00:00
parent 5d86eb64ac
commit f6c06bd0b8
2 changed files with 51 additions and 19 deletions
@@ -138,28 +138,32 @@ var BasicView = AbstractView.extend({
// X2Many case: field is an x2many displayed as a list or
// kanban view, but the related fields haven't been loaded yet.
if ((fieldType === 'one2many' || fieldType === 'many2many')) {
var x2mFieldInfo = record.fieldsInfo[this.viewType][name];
var viewType = x2mFieldInfo.viewType || x2mFieldInfo.mode;
var knownFields = Object.keys(record.data[name].fieldsInfo[record.data[name].viewType] || {});
var newFields = Object.keys(record.data[name].fieldsInfo[viewType]);
if (_.difference(newFields, knownFields).length) {
if (!('fieldsInfo' in record.data[name])) {
fieldNames.push(name);
}
} else {
var x2mFieldInfo = record.fieldsInfo[this.viewType][name];
var viewType = x2mFieldInfo.viewType || x2mFieldInfo.mode;
var knownFields = Object.keys(record.data[name].fieldsInfo[record.data[name].viewType] || {});
var newFields = Object.keys(record.data[name].fieldsInfo[viewType]);
if (_.difference(newFields, knownFields).length) {
fieldNames.push(name);
}
if (record.data[name].viewType === 'default') {
// Use case: x2many (tags) in x2many list views
// When opening the x2many record form view, the
// x2many will be reloaded but it may not have
// the same fields (ex: tags in list and list in
// form) so we need to merge the fieldsInfo to
// avoid losing the initial fields (display_name)
var fieldViews = fieldInfo.views || fieldInfo.fieldsInfo || {};
var defaultFieldInfo = record.data[name].fieldsInfo.default;
_.each(fieldViews, function (fieldView) {
_.each(fieldView.fieldsInfo, function (x2mFieldInfo) {
_.defaults(x2mFieldInfo, defaultFieldInfo);
if (record.data[name].viewType === 'default') {
// Use case: x2many (tags) in x2many list views
// When opening the x2many record form view, the
// x2many will be reloaded but it may not have
// the same fields (ex: tags in list and list in
// form) so we need to merge the fieldsInfo to
// avoid losing the initial fields (display_name)
var fieldViews = fieldInfo.views || fieldInfo.fieldsInfo || {};
var defaultFieldInfo = record.data[name].fieldsInfo.default;
_.each(fieldViews, function (fieldView) {
_.each(fieldView.fieldsInfo, function (x2mFieldInfo) {
_.defaults(x2mFieldInfo, defaultFieldInfo);
});
});
});
}
}
}
// Many2one: context is not the same between the different views
@@ -5508,6 +5508,34 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
QUnit.test('nested x2many (non inline views and no widget on inner x2many in list)', async function (assert) {
assert.expect(5);
this.data.partner.records[0].p = [1];
const form = await createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form><field name="p"/></form>',
archs: {
'partner,false,list': '<tree><field name="turtles"/></tree>',
'partner,false,form': '<form><field name="turtles" widget="many2many_tags"/></form>',
},
res_id: 1,
});
assert.containsOnce(form, '.o_data_row');
assert.strictEqual(form.$('.o_data_row').text(), '1 record');
await testUtils.dom.click(form.$('.o_data_row'));
assert.containsOnce(document.body, '.modal .o_form_view');
assert.containsOnce(document.body, '.modal .o_form_view .o_field_many2manytags .badge');
assert.strictEqual($('.modal .o_field_many2manytags').text().trim(), 'donatello');
form.destroy();
});
QUnit.test('one2many (who contains display_name) with tree view and without form view', async function (assert) {
assert.expect(1);