[FIX] web: BasicModel: correctly apply x2many changes
Suppose that we have a form view with a one2many list (non editable) containing a record. In edit mode, the user clicks on that record to edit it in a form view (in a dialog). In this form view, there is an x2many field that isn't in the list. Before this rev., it crashed when the user clicked on 'Save' in the dialog after editing the value of the x2many. This was because the basic model didn't use the correct fieldsInfo in that case (it use the fieldsInfo of the list view instead of the one of the form view, and the x2many field isn't in the list). Also ensures that the record is correctly saved even if editing the x2many is the only change done, as this wasn't the case before.
This commit is contained in:
@@ -908,7 +908,7 @@ var BasicModel = AbstractModel.extend({
|
||||
for (var fieldName in changes) {
|
||||
field = record.fields[fieldName];
|
||||
if (field.type === 'one2many' || field.type === 'many2many') {
|
||||
defs.push(this._applyX2ManyChange(record, fieldName, changes[fieldName]));
|
||||
defs.push(this._applyX2ManyChange(record, fieldName, changes[fieldName], viewType));
|
||||
} else if (field.type === 'many2one') {
|
||||
defs.push(this._applyMany2OneChange(record, fieldName, changes[fieldName]));
|
||||
} else {
|
||||
@@ -1112,13 +1112,15 @@ var BasicModel = AbstractModel.extend({
|
||||
* @param {string} fieldName
|
||||
* @param {Object} command A command object. It should have a 'operation'
|
||||
* key. For example, it looks like {operation: ADD, id: 'partner_1'}
|
||||
* @param {string} [viewType] current viewType. If not set, we will assume
|
||||
* main viewType from the record
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
_applyX2ManyChange: function (record, fieldName, command) {
|
||||
_applyX2ManyChange: function (record, fieldName, command, viewType) {
|
||||
var self = this;
|
||||
var list = this.localData[record._changes[fieldName] || record.data[fieldName]];
|
||||
var field = record.fields[fieldName];
|
||||
var fieldInfo = record.fieldsInfo[record.viewType][fieldName];
|
||||
var fieldInfo = record.fieldsInfo[viewType || record.viewType][fieldName];
|
||||
var view = fieldInfo.views && fieldInfo.views[fieldInfo.mode];
|
||||
var rec;
|
||||
var defs = [];
|
||||
@@ -1939,8 +1941,8 @@ var BasicModel = AbstractModel.extend({
|
||||
// generate update commands for records that have been
|
||||
// updated (it may happen with editable lists)
|
||||
_.each(relData, function (relRecord) {
|
||||
if (!_.isEmpty(relRecord._changes)) {
|
||||
var changes = self._generateChanges(relRecord);
|
||||
var changes = self._generateChanges(relRecord);
|
||||
if (!_.isEmpty(changes)) {
|
||||
var command = x2ManyCommands.update(relRecord.res_id, changes);
|
||||
commands[fieldName].push(command);
|
||||
}
|
||||
@@ -1958,8 +1960,8 @@ var BasicModel = AbstractModel.extend({
|
||||
if (_.contains(keptIds, relIds[i])) {
|
||||
// this is an id that already existed
|
||||
relRecord = _.findWhere(relData, {res_id: relIds[i]});
|
||||
if (!_.isEmpty(relRecord._changes)) {
|
||||
changes = this._generateChanges(relRecord);
|
||||
changes = this._generateChanges(relRecord);
|
||||
if (!_.isEmpty(changes)) {
|
||||
command = x2ManyCommands.update(relRecord.res_id, changes);
|
||||
didChange = true;
|
||||
} else {
|
||||
|
||||
@@ -3103,6 +3103,63 @@ QUnit.module('relational_fields', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('one2many with x2many in form view (but not in list view)', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
// avoid error when saving the edited related record (because the
|
||||
// related x2m field is unknown in the inline list view)
|
||||
// also ensure that the changes are correctly saved
|
||||
|
||||
this.data.turtle.fields.o2m = {string: "o2m", type: "one2many", relation: 'user'};
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<group>' +
|
||||
'<field name="turtles">' +
|
||||
'<tree>' +
|
||||
'<field name="turtle_foo"/>' +
|
||||
'</tree>' +
|
||||
'</field>' +
|
||||
'</group>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
archs: {
|
||||
"turtle,false,form": '<form string="Turtles">' +
|
||||
'<field name="partner_ids" widget="many2many_tags"/>' +
|
||||
'</form>',
|
||||
},
|
||||
viewOptions: {
|
||||
mode: 'edit',
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'write') {
|
||||
assert.deepEqual(args.args[1].turtles, [[1, 2, {
|
||||
partner_ids: [[6, false, [2, 4, 1]]],
|
||||
}]]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
form.$('.o_data_row:first').click(); // edit first record
|
||||
|
||||
var $input = $('.modal .o_field_many2manytags input');
|
||||
$input.click(); // opens the dropdown
|
||||
$input.autocomplete('widget').find('li').click(); // add 'first record'
|
||||
|
||||
// add a many2many tag and save
|
||||
$('.modal .o_field_x2many_list_row_add a').click();
|
||||
$('.modal .o_field_widget[name=name]').val('test').trigger('input');
|
||||
$('.modal .modal-footer .btn-primary').click(); // save
|
||||
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('one2many (who contains display_name) with tree view and without form view', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user