[FIX] web: don't discard x2many rows coming from default_get

Problem occured in the MRP Production wizard (with a consumed
product tracked by serial number). The opened record is a new
record, and its one2many has 2 default rows that are prefilled.
If the user edited one of the quantities in those rows, and set
an invalid value instead (e.g. a letter), the row was removed
without notice when it was focused out. This was because the
model wasn't aware that a change has been done on the record,
and as the record was flagged as new, it was simply abandonned.
This commit is contained in:
Aaron Bohy
2017-09-30 15:59:24 +02:00
parent 16eb262c60
commit 776bac6a06
4 changed files with 57 additions and 0 deletions
@@ -407,6 +407,7 @@ var AbstractField = Widget.extend({
this._isValid = true;
} catch (e) {
this._isValid = false;
this.trigger_up('set_dirty', {dataPointID: this.dataPointID});
return $.Deferred().reject();
}
if (!(options && options.forceChange) && this._isSameValue(value)) {
@@ -19,6 +19,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
custom_events: _.extend({}, AbstractController.prototype.custom_events, FieldManagerMixin.custom_events, {
discard_changes: '_onDiscardChanges',
reload: '_onReload',
set_dirty: '_onSetDirty',
sidebar_data_asked: '_onSidebarDataAsked',
translate: '_onTranslate',
}),
@@ -553,6 +554,14 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
});
}
},
/**
* @private
* @param {OdooEvent} ev
*/
_onSetDirty: function (ev) {
ev.stopPropagation(); // prevent other controllers from handling this request
this.model.setDirty(ev.data.dataPointID);
},
/**
* Handler used to get all the data necessary when a custom action is
* performed through the sidebar.
@@ -947,6 +947,17 @@ var BasicModel = AbstractModel.extend({
record.fields = _.defaults(record.fields, viewInfo.fields);
record.fieldsInfo = _.defaults(record.fieldsInfo, viewInfo.fieldsInfo);
},
/**
* Manually sets a resource as dirty. This is used to notify that a field
* has been modified, but with an invalid value. In that case, the value is
* not sent to the basic model, but the record should still be flagged as
* dirty so that it isn't discarded without any warning.
*
* @param {string} id a resource id
*/
setDirty: function (id) {
this.localData[id]._isDirty = true;
},
/**
* For list resources, this changes the orderedBy key.
*
@@ -6168,6 +6168,42 @@ QUnit.module('relational_fields', {
form.destroy();
});
QUnit.test('one2many with default value: edit line to make it invalid', function (assert) {
assert.expect(3);
this.data.partner.fields.p.default = [
[0, false, {foo: "coucou", int_field: 5}],
];
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch:'<form string="Partners">' +
'<field name="p">' +
'<tree editable="bottom">' +
'<field name="foo"/>' +
'<field name="int_field"/>' +
'</tree>' +
'</field>' +
'</form>',
});
// edit the line and enter an invalid value for int_field
form.$('.o_data_row .o_data_cell:nth(1)').click();
form.$('.o_field_widget[name=int_field]').val('e').trigger('input');
form.$el.click(); // try to validate the line
assert.strictEqual(form.$('.o_data_row.o_selected_row').length, 1,
"line should not have been removed and should still be in edition");
assert.strictEqual($('.modal').length, 1,
"a confirmation dialog should be opened");
assert.ok(form.$('.o_field_widget[name=int_field]').hasClass('o_field_invalid'),
"should indicate that int_field is invalid");
form.destroy();
});
QUnit.module('FieldMany2Many');
QUnit.test('many2many kanban: edition', function (assert) {