[FIX] web: properly react when save operation fails (form)

Before this commit, the save method in the basic model did not properly
react when the rpc fails.  In that case, the returned deferred stayed
indefinitely in the 'pending' state.  This is a big problem, because the
basic controller put that deferred in a mutex.  As a result, every
subsequent operations (including field changes!) were indefinitely delayed.

To reproduce the issue, you can find any form view where some python
business logic will cause a fail in some cases.  For example, create a
new inventory adjustement, click on 'Start inventory', then add a line
in the x2many with the same product as another line.  Saving that record
will fail, but then, the form view is broken: no interaction will work.
This commit is contained in:
Géry Debongnie
2017-05-26 15:02:36 +02:00
parent dcde0aaf30
commit 1d57f89380
2 changed files with 44 additions and 1 deletions
@@ -778,7 +778,7 @@ var BasicModel = AbstractModel.extend({
_.extend(record.data, _changes);
def.resolve(changedFields);
}
});
}).fail(def.reject.bind(def));
} else {
def.resolve(changedFields);
}
@@ -4575,5 +4575,48 @@ QUnit.module('Views', {
form.destroy();
});
QUnit.test('form view is not broken if save operation fails', function (assert) {
assert.expect(5);
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form string="Partners">' +
'<sheet>' +
'<group>' +
'<field name="foo"/>' +
'</group>' +
'</sheet>' +
'</form>',
res_id: 1,
mockRPC: function (route, args) {
assert.step(args.method);
if (args.method === 'write' && args.args[1].foo === 'incorrect value') {
return $.Deferred().reject();
}
return this._super.apply(this, arguments);
},
});
form.$buttons.find('.o_form_button_edit').click();
form.$('input[name="foo"]').val("incorrect value").trigger("input");
form.$buttons.find('.o_form_button_save').click();
form.$('input[name="foo"]').val("correct value").trigger("input");
form.$buttons.find('.o_form_button_save').click();
assert.verifySteps([
'read', // initial read to render the view
'write', // write on save (it fails, does not trigger a read)
'write', // write on save (it works)
'read' // read on reload
]);
form.destroy();
});
});
});