diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index 3b35c994443..ec64eb9b7ad 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -1233,7 +1233,10 @@ var BasicModel = AbstractModel.extend({ }).then(function (result) { result = result[0]; record.data = _.extend({}, record.data, result); - return self._postprocess(record); + }).then(function () { + return self._fetchX2Manys(record, oldData, fieldNames).then(function () { + return self._postprocess(record); + }); }).then(function (record) { _.each(fieldNames, function (name) { var field = record.fields[name]; @@ -1262,10 +1265,7 @@ var BasicModel = AbstractModel.extend({ record.data[name] = fieldUtils.parse.datetime(val); } }); - }).then(function () { - return self._fetchX2Manys(record, oldData, fieldNames).then(function () { - return record; - }); + return record; }); }, /** @@ -1549,7 +1549,12 @@ var BasicModel = AbstractModel.extend({ */ _getContext: function (element, options) { var context = new Context(session.user_context, element.context); - context.set_eval_context(element.data); + var evalContext = this.get(element.id, {raw: true}).data; + if (element.parentID) { + var parent = this.get(element.parentID, {raw: true}); + _.extend(evalContext, {parent: parent.data}); + } + context.set_eval_context(evalContext); if (options && options.fieldName) { var attrs = element.fieldAttrs[options.fieldName]; if (attrs && attrs.context) { diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index 9943ba02ec8..8a630e30905 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -419,6 +419,7 @@ var FormController = BasicController.extend({ fields_view: field.views ? field.views.form : undefined, form_view_options: {'not_interactible_on_create': true}, model: this.model, + parentID: this.handle, }).open(); }, /** @@ -535,6 +536,8 @@ var FormController = BasicController.extend({ title: _t("Open: ") + event.data.string, on_save: event.data.on_save, on_saved: event.data.on_saved, + model: self.model, + parentID: self.handle, }).open(); }); }, diff --git a/addons/web/static/src/js/views/form/form_view.js b/addons/web/static/src/js/views/form/form_view.js index ca667f6886d..20eef83c797 100644 --- a/addons/web/static/src/js/views/form/form_view.js +++ b/addons/web/static/src/js/views/form/form_view.js @@ -23,6 +23,7 @@ var FormView = BasicView.extend({ var mode = params.mode || (params.currentId ? 'readonly' : 'edit'); this.loadParams.type = 'record'; + this.loadParams.parentID = params.parentID; this.controllerParams.hasSidebar = params.sidebar; this.controllerParams.toolbar = false; diff --git a/addons/web/static/src/js/views/view_dialogs.js b/addons/web/static/src/js/views/view_dialogs.js index 4274d37291e..f5982e2ef65 100644 --- a/addons/web/static/src/js/views/view_dialogs.js +++ b/addons/web/static/src/js/views/view_dialogs.js @@ -67,6 +67,10 @@ var FormViewDialog = ViewDialog.extend({ /** * @param {Widget} parent * @param {Object} [options] + * @param {string} [options.parentID] the id of the parent record. It is + * useful for situations such as a one2many opened in a form view dialog. + * In that case, we want to be able to properly evaluate domains with the + * 'parent' key. * @param {integer} [options.res_id] the id of the record to open * @param {Object} [options.form_view_options] dict of options to pass to * the Form View @todo: make it work @@ -86,6 +90,7 @@ var FormViewDialog = ViewDialog.extend({ this.on_saved = options.on_saved || (function () {}); this.context = options.context; this.model = options.model; + this.parentID = options.parentID; var multi_select = !_.isNumber(options.res_id) && !options.disable_multiple_selection; var readonly = _.isNumber(options.res_id) && options.readonly; @@ -158,6 +163,7 @@ var FormViewDialog = ViewDialog.extend({ footer_to_buttons: true, default_buttons: false, model: self.model, + parentID: self.parentID, }); return formview.createController(self); }).then(function (formView) { diff --git a/addons/web/static/test/fields/relational_fields_tests.js b/addons/web/static/test/fields/relational_fields_tests.js index c76c5bdebe0..63dc28f697d 100644 --- a/addons/web/static/test/fields/relational_fields_tests.js +++ b/addons/web/static/test/fields/relational_fields_tests.js @@ -1359,6 +1359,49 @@ QUnit.module('relational_fields', { form.$buttons.find('.o_form_button_save').click(); }); + QUnit.test('one2many list with inline form view with context with parent key', function (assert) { + assert.expect(2); + + this.data.partner.records[0].p = [2]; + this.data.partner.records[0].product_id = 41; + this.data.partner.records[1].product_id = 37; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '', + res_id: 1, + mockRPC: function (route, args) { + if (args.method === 'name_search') { + assert.strictEqual(args.kwargs.context.partner_foo, "yop", + "should have correctly evaluated parent foo field"); + assert.strictEqual(args.kwargs.context.lalala, 41, + "should have correctly evaluated parent product_id field"); + } + return this._super.apply(this, arguments); + }, + }); + + form.$buttons.find('.o_form_button_edit').click(); + // open a modal + form.$('tr.o_data_row:eq(0) td:contains(xphone)').click(); + + // write in the many2one field + $('.modal .o_form_field_many2one input').click(); + }); + QUnit.test('one2many list edition, some basic functionality', function (assert) { assert.expect(3);