[FIX] web: BasicModel: send correct context

... when reading and writing on a record (especially inside lists).

Before this rev., the context sent when reading a record, and when
writing records inside lists (editable list views) wasn't correct.
This caused an issue in Sales > Products (variant activated) >
open a product with variants > click on variant prices > edit the
prices of a variant: the value wasn't saved correctly (because the
inverse function requires 'active_id' to be in the context and it
wasn't the case).
This commit is contained in:
Aaron Bohy
2017-06-29 14:58:04 +02:00
parent 2846887ea8
commit b954cd6483
4 changed files with 129 additions and 11 deletions
@@ -1546,7 +1546,7 @@ var BasicModel = AbstractModel.extend({
model: record.model,
method: 'read',
args: [[record.res_id], fieldNames],
context: _.extend({}, record.context, {bin_size: true}),
context: _.extend({}, record.getContext(), {bin_size: true}),
})
.then(function (result) {
if (result.length === 0) {
@@ -2505,8 +2505,13 @@ var BasicModel = AbstractModel.extend({
continue;
}
if (field.type === 'one2many' || field.type === 'many2many') {
relDataPoint = this._applyX2ManyOperations(this.localData[context[fieldName]]);
var ids = relDataPoint.res_ids.slice(0);
var ids;
if (!context[fieldName] || _.isArray(context[fieldName])) { // no dataPoint created yet
ids = context[fieldName] || [];
} else {
relDataPoint = this._applyX2ManyOperations(this.localData[context[fieldName]]);
ids = relDataPoint.res_ids.slice(0);
}
if (!forDomain) {
// when sent to the server, the x2manys values must be a list
// of commands in a context, but the list of ids in a domain
@@ -3159,7 +3164,7 @@ var BasicModel = AbstractModel.extend({
model: list.model,
method: 'read',
args: [missingIds, fieldNames],
context: {} // FIXME
context: list.getContext(),
});
} else {
def = $.when(_.map(missingIds, function (id) {
@@ -3177,6 +3182,7 @@ var BasicModel = AbstractModel.extend({
dataPoint = self.localData[list._cache[id]];
} else {
dataPoint = self._makeDataPoint({
context: list.context,
data: _.findWhere(records, {id: id}),
fieldsInfo: list.fieldsInfo,
fields: list.fields,
@@ -3233,7 +3239,7 @@ var BasicModel = AbstractModel.extend({
route: '/web/dataset/search_read',
model: list.model,
fields: fieldNames,
context: list.context,
context: list.getContext(),
domain: list.domain || [],
limit: list.limit,
offset: list.loadMoreOffset + list.offset,
@@ -3244,6 +3250,7 @@ var BasicModel = AbstractModel.extend({
var ids = _.pluck(result.records, 'id');
var data = _.map(result.records, function (record) {
var dataPoint = self._makeDataPoint({
context: list.context,
data: record,
fields: list.fields,
fieldsInfo: list.fieldsInfo,
@@ -4658,6 +4658,61 @@ QUnit.module('relational_fields', {
form.destroy();
});
QUnit.test('editable list: contexts are correctly sent', function (assert) {
assert.expect(5);
this.data.partner.records[0].timmy = [12];
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form>' +
'<field name="foo"/>' +
'<field name="timmy" context="{\'key\': parent.foo}">' +
'<tree editable="top">' +
'<field name="display_name"/>' +
'</tree>' +
'</field>' +
'</form>',
mockRPC: function (route, args) {
if (args.method === 'read' && args.model === 'partner') {
assert.deepEqual(args.kwargs.context, {
active_field: 2,
bin_size: true,
someKey: 'some value',
}, "sent context should be correct");
}
if (args.method === 'read' && args.model === 'partner_type') {
assert.deepEqual(args.kwargs.context, {
key: 'yop',
someKey: 'some value',
}, "sent context should be correct");
}
if (args.method === 'write') {
assert.deepEqual(args.kwargs.context, {
active_field: 2,
someKey: 'some value',
}, "sent context should be correct");
}
return this._super.apply(this, arguments);
},
session: {
user_context: {someKey: 'some value'},
},
viewOptions: {
mode: 'edit',
context: {active_field: 2},
},
res_id: 1,
});
form.$('.o_data_cell:first').click();
form.$('.o_field_widget[name=display_name]').val('abc').trigger('input');
form.$buttons.find('.o_form_button_save').click();
form.destroy();
});
QUnit.module('FieldMany2Many');
QUnit.test('many2many kanban: edition', function (assert) {
@@ -72,9 +72,15 @@ QUnit.module('Views', {
Model: BasicModel,
data: this.data,
mockRPC: function (route, args) {
assert.strictEqual(args.kwargs.context.active_field, 2,
"should have sent the correct context");
assert.deepEqual(args.kwargs.context, {
active_field: 2,
bin_size: true,
someKey: 'some value',
}, "should have sent the correct context");
return this._super.apply(this, arguments);
},
session: {
user_context: {someKey: 'some value'},
}
});
@@ -1790,9 +1796,23 @@ QUnit.module('Views', {
this.data.partner.records[0].product_ids = [37, 41];
this.params.fieldNames = Object.keys(this.data.partner.fields);
this.params.fieldsInfo = {
form: {
qux: {
context: "{'category': category, 'product_ids': product_ids}",
domain: "[['id', 'in', category], ['id', 'in', product_ids]]",
relatedFields: this.data.partner.fields,
},
category: {
relatedFields: this.data.partner_type.fields,
},
product_ids: {
relatedFields: this.data.product.fields,
},
},
};
this.params.viewType = 'form';
this.params.res_id = 1;
this.params.context = "{'category': category, 'product_ids': product_ids}";
this.params.domain = "[['id', 'in', category], ['id', 'in', product_ids]]";
var model = createModel({
Model: BasicModel,
@@ -1801,8 +1821,8 @@ QUnit.module('Views', {
model.load(this.params).then(function (resultID) {
var record = model.get(resultID);
var context = record.getContext();
var domain = record.getDomain();
var context = record.getContext({fieldName: 'qux'});
var domain = record.getDomain({fieldName: 'qux'});
assert.deepEqual(context, {
category: [12],
@@ -2,6 +2,7 @@ odoo.define('web.list_tests', function (require) {
"use strict";
var config = require('web.config');
var FormView = require('web.FormView');
var ListView = require('web.ListView');
var testUtils = require('web.test_utils');
@@ -2430,6 +2431,41 @@ QUnit.module('Views', {
list.destroy();
});
QUnit.test('editable list view: contexts are correctly sent', function (assert) {
assert.expect(6);
var list = createView({
View: ListView,
model: 'foo',
data: this.data,
arch: '<tree editable="top">' +
'<field name="foo"/>' +
'</tree>',
mockRPC: function (route, args) {
var context;
if (route === '/web/dataset/search_read') {
context = args.context;
} else {
context = args.kwargs.context;
}
assert.strictEqual(context.active_field, 2, "context should be correct");
assert.strictEqual(context.someKey, 'some value', "context should be correct");
return this._super.apply(this, arguments);
},
session: {
user_context: {someKey: 'some value'},
},
viewOptions: {
context: {active_field: 2},
},
});
list.$('.o_data_cell:first').click();
list.$('.o_field_widget[name=foo]').val('abc').trigger('input');
list.$buttons.find('.o_list_button_save').click();
list.destroy();
});
});
});