[FIX] web: Many2one in X2Manys: quick create then save line
A problem occured with a required Many2One inside an X2Many (e.g. order_line field in sale.order form view). If the user clicked on 'Add an item' to add a row, then typed some text in the Many2One, then clicked on 'Create ...' to quick create a new product, and then directly clicked on 'Add an item' to add another row (before the name_create returned), the first row was discarded. This was because before the name_create returns, the Many2one still has no value, and as it is required, the row was considered invalid and then discarded. This rev. ensures to wait for the name_create to return before trying to save the row and to create a new one.
This commit is contained in:
@@ -619,12 +619,15 @@ var FieldX2Many = AbstractField.extend({
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
commitChanges: function () {
|
||||
var self = this;
|
||||
var inEditionRecordID =
|
||||
this.renderer
|
||||
&& this.renderer.viewType === "list"
|
||||
&& this.renderer.getEditableRecordID();
|
||||
if (inEditionRecordID) {
|
||||
return this._saveLine(inEditionRecordID);
|
||||
return this.renderer.commitChanges(inEditionRecordID).then(function () {
|
||||
return self._saveLine(inEditionRecordID);
|
||||
});
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
@@ -767,21 +770,17 @@ var FieldX2Many = AbstractField.extend({
|
||||
* did not agree to discard.
|
||||
*/
|
||||
_saveLine: function (recordID) {
|
||||
var self = this;
|
||||
var def = $.Deferred();
|
||||
this.renderer.commitChanges(recordID).then(function () { // TODO wrong as no mutex protection
|
||||
var fieldNames = self.renderer.canBeSaved(recordID);
|
||||
if (fieldNames.length) {
|
||||
self.trigger_up('discard_changes', {
|
||||
recordID: recordID,
|
||||
onSuccess: def.resolve.bind(def),
|
||||
onFailure: def.reject.bind(def),
|
||||
});
|
||||
} else {
|
||||
self.renderer.setRowMode(recordID, 'readonly')
|
||||
.done(def.resolve.bind(def));
|
||||
}
|
||||
});
|
||||
var fieldNames = this.renderer.canBeSaved(recordID);
|
||||
if (fieldNames.length) {
|
||||
this.trigger_up('discard_changes', {
|
||||
recordID: recordID,
|
||||
onSuccess: def.resolve.bind(def),
|
||||
onFailure: def.reject.bind(def),
|
||||
});
|
||||
} else {
|
||||
this.renderer.setRowMode(recordID, 'readonly').done(def.resolve.bind(def));
|
||||
}
|
||||
return def;
|
||||
},
|
||||
|
||||
@@ -900,9 +899,15 @@ var FieldX2Many = AbstractField.extend({
|
||||
ev.stopPropagation();
|
||||
this.trigger_up('mutexify', {
|
||||
action: function () {
|
||||
return self._saveLine(ev.data.recordID)
|
||||
.done(ev.data.onSuccess)
|
||||
.fail(ev.data.onFailure);
|
||||
return self.renderer.commitChanges(ev.data.recordID).then(function () {
|
||||
self.trigger_up('mutexify', {
|
||||
action: function () {
|
||||
return self._saveLine(ev.data.recordID)
|
||||
.done(ev.data.onSuccess)
|
||||
.fail(ev.data.onFailure);
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -922,7 +927,7 @@ var FieldX2Many = AbstractField.extend({
|
||||
id: rowID,
|
||||
data: data,
|
||||
});
|
||||
})
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Adds field name information to the event, so that the view upstream is
|
||||
|
||||
@@ -659,6 +659,87 @@ QUnit.module('relational_fields', {
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('list in form: quick create then add a new line directly', function (assert) {
|
||||
// required many2one inside a one2many list: directly after quick creating
|
||||
// a new many2one value (before the name_create returns), click on add an item:
|
||||
// at this moment, the many2one has still no value, and as it is required,
|
||||
// the row is discarded if a saveLine is requested. However, it should
|
||||
// wait for the name_create to return before trying to save the line.
|
||||
var done = assert.async();
|
||||
assert.expect(8);
|
||||
|
||||
this.data.partner.onchanges = {
|
||||
trululu: function () {},
|
||||
};
|
||||
|
||||
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
|
||||
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
|
||||
|
||||
var def = $.Deferred();
|
||||
var newRecordID;
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form>' +
|
||||
'<sheet>' +
|
||||
'<field name="p">' +
|
||||
'<tree editable="bottom">' +
|
||||
'<field name="trululu" required="1"/>' +
|
||||
'</tree>' +
|
||||
'</field>' +
|
||||
'</sheet>' +
|
||||
'</form>',
|
||||
mockRPC: function (route, args) {
|
||||
var result = this._super.apply(this, arguments);
|
||||
if (args.method === 'name_create') {
|
||||
return def.then(_.constant(result)).then(function (nameGet) {
|
||||
newRecordID = nameGet[0];
|
||||
return nameGet;
|
||||
});
|
||||
}
|
||||
if (args.method === 'create') {
|
||||
assert.deepEqual(args.args[0].p[0][2].trululu, newRecordID);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
});
|
||||
|
||||
form.$('.o_field_x2many_list_row_add a').click();
|
||||
|
||||
var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
|
||||
form.$('.o_field_many2one input').val('b').trigger('keydown');
|
||||
concurrency.delay(0).then(function () {
|
||||
$dropdown.find('li:first()').click(); // quick create 'b'
|
||||
form.$('.o_field_x2many_list_row_add a').click();
|
||||
|
||||
assert.strictEqual(form.$('.o_data_row').length, 1,
|
||||
"there should still be only one row");
|
||||
assert.ok(form.$('.o_data_row').hasClass('o_selected_row'),
|
||||
"the row should still be in edition");
|
||||
|
||||
def.resolve();
|
||||
|
||||
assert.strictEqual(form.$('.o_data_row:first .o_data_cell').text(), 'b',
|
||||
"first row should have the correct m2o value");
|
||||
assert.strictEqual(form.$('.o_data_row').length, 2,
|
||||
"there should now be 2 rows");
|
||||
assert.ok(form.$('.o_data_row:nth(1)').hasClass('o_selected_row'),
|
||||
"the second row should be in edition");
|
||||
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
|
||||
assert.strictEqual(form.$('.o_data_row').length, 1,
|
||||
"there should be 1 row saved (the second one was empty and invalid)");
|
||||
assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'b',
|
||||
"should have the correct m2o value");
|
||||
|
||||
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
|
||||
form.destroy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('autocompletion in a many2one, in form view with a domain', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user