[FIX] web,*: send correct context on button clicked

*account_asset

When a button of type 'action' is clicked (execute a given action),
special keys must be set in the context (active_id, active_ids and
active_model). They must be computed regarding the record containing
the clicked button, i.e. if we are in a modal, it must be the id
and model of the record displayed in the modal.

Before this rev., we always sent the id and model of the record
displayed in the background (i.e. the id and model of the url).

This caused a bug in MRP that could be reproduced as follows:
- open a manufacturing order in form view
- click on edit
- click on one of the line of the one2many, and click on the green
  icon to edit a product
- click on the update product quantity button on top of it
- the product field must be correctly filled, which was not the
  case before this rev.
This commit is contained in:
Aaron Bohy
2017-08-10 08:48:32 +02:00
committed by David Monjoie
parent 50957038b9
commit 1e8f6d01ff
7 changed files with 102 additions and 37 deletions
@@ -125,7 +125,7 @@ QUnit.test('basic rendering', function (assert) {
});
QUnit.test('click events are correctly triggered', function (assert) {
assert.expect(3);
assert.expect(2);
var form = createView({
View: FormView,
@@ -146,8 +146,7 @@ QUnit.test('click events are correctly triggered', function (assert) {
intercepts: {
execute_action: function (event) {
var data = event.data;
assert.strictEqual(data.model, 'line', "should have correct model");
assert.deepEqual(data.res_ids, [4], "should have correct res_ids");
assert.strictEqual(data.env.model, 'line', "should have correct model");
assert.strictEqual(data.action_data.name, 'create_move',
"should call correct method");
},
+18 -15
View File
@@ -20,7 +20,7 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
custom_events: {
execute_action: function(event) {
var data = event.data;
this.do_execute_action(data.action_data, data.model, data.res_ids, data.on_closed)
this.do_execute_action(data.action_data, data.env, data.on_closed)
.then(data.on_success, data.on_fail);
},
search: function(event) {
@@ -551,16 +551,19 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
* @param {String} [action_data.special=null] special action handlers (currently: only ``'cancel'``)
* @param {String} [action_data.type='workflow'] the action type, if present, one of ``'object'``, ``'action'`` or ``'workflow'``
* @param {Object} [action_data.context=null] additional action context, to add to the current context
* @param {DataSet} dataset a dataset object used to communicate with the server
* @param {integer[]} [res_ids] the res_ids of the objects on which the action is to be applied (fallback on env.ids if not set)
* @param {Object} env
* @param {string} env.model the model of the record(s) triggering the action
* @param {integer[]} [env.resIDs] the current ids in the environment where the action is triggered
* @param {integer} [env.currentID] the id of the record triggering the action
* @param {Object} [env.context] a context to pass to the action
* @param {Function} on_closed callback to execute when dialog is closed or when the action does not generate any result (no new action)
*/
do_execute_action: function (action_data, model, res_ids, on_closed) {
do_execute_action: function (action_data, env, on_closed) {
var self = this;
var result_handler = on_closed || function () {};
var context = new Context(this.env.context, action_data.context || {});
var context = new Context(env.context, action_data.context || {});
// OR NULL hereunder: pyeval waits specifically for a null value, different from undefined
var record_id = res_ids && res_ids[0] || null;
var recordID = env.currentID || null;
// response handler
var handler = function (action) {
@@ -574,11 +577,11 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
}))
);
ncontext.add(action_data.context || {});
ncontext.add({active_model: self.env.modelName});
if (res_ids) {
ncontext.add({active_model: env.model});
if (recordID) {
ncontext.add({
active_id: record_id,
active_ids: res_ids,
active_id: recordID,
active_ids: [recordID],
});
}
ncontext.add(action.context || {});
@@ -595,7 +598,7 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
if (action_data.special === 'cancel') {
return handler({"type":"ir.actions.act_window_close"});
} else if (action_data.type === "object") {
var args = res_ids ? [res_ids] : [this.env.ids];
var args = recordID ? [[recordID]] : [env.resIDs];
if (action_data.args) {
try {
// Warning: quotes and double quotes problem due to json and xml clash
@@ -607,13 +610,13 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
}
}
args.push(context);
var dataset = new data.DataSet(this, model, this.env.context);
var dataset = new data.DataSet(this, env.model, env.context);
return dataset.call_button(action_data.name, args).then(handler);
} else if (action_data.type === "action") {
return data_manager.load_action(action_data.name, _.extend(pyeval.eval('context', context), {
active_model: this.env.modelName,
active_ids: this.env.ids,
active_id: record_id,
active_model: env.model,
active_ids: env.resIDs,
active_id: recordID,
})).then(handler);
}
},
@@ -232,13 +232,17 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
return self.isDestroyed() ? $.when() : self.reload();
};
record = record || this.model.get(this.handle);
var recordID = record.data.id;
this.trigger_up('execute_action', {
action_data: _.extend({}, attrs, {
context: record.getContext({additionalContext: attrs.context || {}}),
context: record.getContext({additionalContext: attrs.context || {}}),
}),
model: record.model,
res_ids: [recordID],
env: {
context: record.getContext(),
currentID: record.data.id,
model: record.model,
resIDs: record.res_ids,
},
on_closed: function (reason) {
if (!_.isObject(reason)) {
reload(reason);
@@ -237,8 +237,12 @@ var KanbanController = BasicController.extend({
}
this.trigger_up('execute_action', {
action_data: attrs,
model: record.model,
res_ids: [record.res_id],
env: {
context: record.getContext(),
currentID: record.res_id,
model: record.model,
resIDs: record.res_ids,
},
on_closed: function () {
self.model.reload(record.id).then(function (db_id) {
var data = self.model.get(db_id);
@@ -1002,6 +1002,60 @@ QUnit.module('relational_fields', {
form.destroy();
});
QUnit.test('list in form: call button in sub view', function (assert) {
assert.expect(6);
this.data.partner.records[0].p = [2];
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form>' +
'<sheet>' +
'<field name="p">' +
'<tree editable="bottom">' +
'<field name="product_id"/>' +
'</tree>' +
'</field>' +
'</sheet>' +
'</form>',
res_id: 1,
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/product/get_formview_id') {
return $.when(false);
}
return this._super.apply(this, arguments);
},
intercepts: {
execute_action: function (event) {
assert.strictEqual(event.data.env.model, 'product',
'should call with correct model in env');
assert.strictEqual(event.data.env.currentID, 37,
'should call with correct currentID in env');
assert.deepEqual(event.data.env.resIDs, [37],
'should call with correct resIDs in env');
},
},
archs: {
'product,false,form': '<form string="Partners">' +
'<header>' +
'<button name="action" type="action" string="Just do it !"/>' +
'<button name="object" type="object" string="Just don\'t do it !"/>' +
'<field name="display_name"/>' +
'</header>' +
'</form>',
},
});
form.$buttons.find('.o_form_button_edit').click();
form.$('td.o_data_cell:first').click(); // edit first one2many line
form.$('.o_external_button').click(); // open product sub view in modal
$('button:contains("Just do it !")').click(); // click on action button
$('button:contains("Just don\'t do it !")').click(); // click on object button
form.destroy();
});
QUnit.test('autocompletion in a many2one, in form view with a domain', function (assert) {
assert.expect(1);
@@ -4036,9 +4090,9 @@ QUnit.module('relational_fields', {
res_id: 1,
intercepts: {
execute_action: function (event) {
assert.deepEqual(event.data.res_ids, [2],
assert.deepEqual(event.data.env.currentID, 2,
'should call with correct id');
assert.strictEqual(event.data.model, 'partner',
assert.strictEqual(event.data.env.model, 'partner',
'should call with correct model');
assert.strictEqual(event.data.action_data.name, 'method_name',
"should call correct method");
@@ -4080,9 +4134,9 @@ QUnit.module('relational_fields', {
res_id: 1,
intercepts: {
execute_action: function (event) {
assert.deepEqual(event.data.res_ids, [2],
assert.deepEqual(event.data.env.currentID, 2,
'should call with correct id');
assert.strictEqual(event.data.model, 'partner',
assert.strictEqual(event.data.env.model, 'partner',
'should call with correct model');
assert.strictEqual(event.data.action_data.name, 'method_name',
"should call correct method");
+8 -7
View File
@@ -901,7 +901,7 @@ QUnit.module('Views', {
testUtils.intercept(form, 'execute_action', function (event) {
assert.strictEqual(event.data.action_data.name, "post",
"should trigger execute_action with correct method name");
assert.deepEqual(event.data.res_ids, [2], "should have correct id in event data");
assert.deepEqual(event.data.env.currentID, 2, "should have correct id in event data");
event.data.on_success();
event.data.on_closed();
});
@@ -954,7 +954,7 @@ QUnit.module('Views', {
testUtils.intercept(form, 'execute_action', function (event) {
assert.step('execute_action');
assert.deepEqual(event.data.res_ids, [resID],
assert.deepEqual(event.data.env.currentID, resID,
"execute action should be done on correct record id");
event.data.on_success();
event.data.on_closed();
@@ -1004,7 +1004,7 @@ QUnit.module('Views', {
testUtils.intercept(form, 'execute_action', function (event) {
assert.step('execute_action');
assert.deepEqual(event.data.res_ids, [resID],
assert.deepEqual(event.data.env.currentID, resID,
"execute action should be done on correct record id");
event.data.on_success();
event.data.on_closed();
@@ -3561,8 +3561,9 @@ QUnit.module('Views', {
},
intercepts: {
execute_action: function (e) {
assert.deepEqual(e.data.action_data.context, {test: 2},
"button context should have been evaluated and given to the action, without previous context");
assert.deepEqual(e.data.action_data.context, {
'test': 2
}, "button context should have been evaluated and given to the action, with magicc without previous context");
},
},
});
@@ -3595,8 +3596,8 @@ QUnit.module('Views', {
},
intercepts: {
execute_action: function (e) {
assert.deepEqual(e.data.action_data.context, {},
"button context should have been evaluated and given to the action, without previous context");
assert.deepEqual(e.data.action_data.context, {
}, "button context should have been evaluated and given to the action, with magic keys but without previous context");
},
},
});
+2 -2
View File
@@ -1171,9 +1171,9 @@ QUnit.module('Views', {
},
intercepts: {
execute_action: function (event) {
assert.deepEqual(event.data.res_ids, [1],
assert.deepEqual(event.data.env.currentID, 1,
'should call with correct id');
assert.strictEqual(event.data.model, 'foo',
assert.strictEqual(event.data.env.model, 'foo',
'should call with correct model');
assert.strictEqual(event.data.action_data.name, 'button_action',
"should call correct method");