diff options
| author | Raphael Collet <rco@odoo.com> | 2019-02-14 12:59:04 +0000 |
|---|---|---|
| committer | Raphael Collet <rco@odoo.com> | 2019-03-22 16:42:14 +0000 |
| commit | d87443a21337bcc3d785ae23e19f66b11ba8bb9e (patch) | |
| tree | 0a10e803beca0026560ecb32c18b492c7323de22 | |
| parent | 1ced3bfca457ac50845637bcd42a8e53bd7f088d (diff) | |
[FIX] convert: enable kwargs in tag <function>
closes odoo/odoo#31417
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
| -rw-r--r-- | addons/crm/data/crm_lead_demo.xml | 12 | ||||
| -rw-r--r-- | addons/mass_mailing/data/mass_mailing_demo.xml | 23 | ||||
| -rw-r--r-- | addons/stock/data/stock_data.xml | 20 | ||||
| -rw-r--r-- | odoo/addons/test_convert/__init__.py | 12 | ||||
| -rw-r--r-- | odoo/addons/test_convert/models.py | 20 | ||||
| -rw-r--r-- | odoo/addons/test_convert/tests/test_convert.py | 114 | ||||
| -rw-r--r-- | odoo/import_xml.rng | 1 | ||||
| -rw-r--r-- | odoo/tools/convert.py | 36 |
8 files changed, 177 insertions, 61 deletions
diff --git a/addons/crm/data/crm_lead_demo.xml b/addons/crm/data/crm_lead_demo.xml index 4f638a42f0e..0e73640175a 100644 --- a/addons/crm/data/crm_lead_demo.xml +++ b/addons/crm/data/crm_lead_demo.xml @@ -368,8 +368,8 @@ Andrew</p>]]></field> <!-- Call Function to Cancel the leads (set as Dead) --> <function model="crm.lead" name="action_set_lost" - eval="[ref('crm_case_7'), ref('crm_case_9'), ref('crm_case_11'), ref('crm_case_12')], - {'install_mode': True}"/> + eval="[[ref('crm_case_7'), ref('crm_case_9'), ref('crm_case_11'), ref('crm_case_12')]]" + context="{'install_mode': True}"/> <!-- Demo Opportunities --> <record id="crm_case_13" model="crm.lead"> @@ -1161,13 +1161,13 @@ Andrew</p>]]></field> <!-- Call Function to set dome opportunities as Lost --> <function model="crm.lead" name="action_set_lost" - eval="[ref('crm_case_28')], - {'install_mode': True}"/> + eval="[[ref('crm_case_28')]]" + context="{'install_mode': True}"/> <!-- Call Function to set some opportunities as Won --> <function model="crm.lead" name="action_set_won" - eval="[ref('crm_case_20'), ref('crm_case_23'), ref('crm_case_27')], - {'install_mode': True}"/> + eval="[[ref('crm_case_20'), ref('crm_case_23'), ref('crm_case_27')]]" + context="{'install_mode': True}"/> <!-- Activities --> <record id="activity_1" model="mail.activity"> diff --git a/addons/mass_mailing/data/mass_mailing_demo.xml b/addons/mass_mailing/data/mass_mailing_demo.xml index 19957054c66..e9df5daaa35 100644 --- a/addons/mass_mailing/data/mass_mailing_demo.xml +++ b/addons/mass_mailing/data/mass_mailing_demo.xml @@ -264,34 +264,41 @@ <value model="link.tracker.code" search="[('link_id.url', '=', 'http://www.example.com')]" use="code"/> - <value eval="{'ip': '100.01.02.03', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_0')}"/> + <value name="ip">100.01.02.03</value> + <value name="country_code">BE</value> + <value name="mail_stat_id" eval="ref('mass_mail_1_stat_0')"/> </function> <function model="link.tracker.click" name="add_click"> <value model="link.tracker.code" search="[('link_id.url', '=', 'http://www.example.net/page/contactus')]" use="code"/> - <value eval="{'ip': '100.01.02.03', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_0')}"/> + <value name="ip">100.01.02.03</value> + <value name="country_code">BE</value> + <value name="mail_stat_id" eval="ref('mass_mail_1_stat_0')"/> </function> <function model="link.tracker.click" name="add_click"> <value model="link.tracker.code" search="[('link_id.url', '=', 'http://www.example.com')]" use="code"/> - <value eval="{'ip': '100.01.02.04', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_1')}"/> + <value name="ip">100.01.02.04</value> + <value name="country_code">BE</value> + <value name="mail_stat_id" eval="ref('mass_mail_1_stat_1')"/> </function> <function model="link.tracker.click" name="add_click"> <value model="link.tracker.code" search="[('link_id.url', '=', 'http://www.example.net/page/contactus')]" use="code"/> - <value eval="{'ip': '100.01.02.04', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_0')}"/> - <value eval="'100.01.02.04'"/> - <value eval="'BE'"/> - <value eval="ref('mass_mail_1_stat_0')"/> + <value name="ip">100.01.02.04</value> + <value name="country_code">BE</value> + <value name="mail_stat_id" eval="ref('mass_mail_1_stat_0')"/> </function> <function model="link.tracker.click" name="add_click"> <value model="link.tracker.code" search="[('link_id.url', '=', 'http://www.example.com')]" use="code"/> - <value eval="{'ip': '100.01.02.05', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_2')}"/> + <value name="ip">100.01.02.05</value> + <value name="country_code">BE</value> + <value name="mail_stat_id" eval="ref('mass_mail_1_stat_2')"/> </function> </data> diff --git a/addons/stock/data/stock_data.xml b/addons/stock/data/stock_data.xml index d522f76d9c6..34693a1c29f 100644 --- a/addons/stock/data/stock_data.xml +++ b/addons/stock/data/stock_data.xml @@ -143,20 +143,10 @@ </function> <!-- create the transit location for each company existing --> - <function model="res.company" name="create_missing_transit_location"> - <value model="res.company" eval="obj()"/> - </function> - <function model="res.company" name="create_missing_warehouse"> - <value model="res.company" eval="obj()"/> - </function> - <function model="res.company" name="create_missing_inventory_loss_location"> - <value model="res.company" eval="obj()"/> - </function> - <function model="res.company" name="create_missing_production_location"> - <value model="res.company" eval="obj()"/> - </function> - <function model="res.company" name="create_missing_scrap_location"> - <value model="res.company" eval="obj()"/> - </function> + <function model="res.company" name="create_missing_transit_location"/> + <function model="res.company" name="create_missing_warehouse"/> + <function model="res.company" name="create_missing_inventory_loss_location"/> + <function model="res.company" name="create_missing_production_location"/> + <function model="res.company" name="create_missing_scrap_location"/> </data> </odoo> diff --git a/odoo/addons/test_convert/__init__.py b/odoo/addons/test_convert/__init__.py index a301ab24b52..dc5e6b693d1 100644 --- a/odoo/addons/test_convert/__init__.py +++ b/odoo/addons/test_convert/__init__.py @@ -1,10 +1,4 @@ -from odoo import fields, models +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. - -class Usered(models.Model): - _name = 'test_convert.usered' - _description = "z test model ignore" - - name = fields.Char() - user_id = fields.Many2one('res.users', default=lambda self: self.env.user) - tz = fields.Char(default=lambda self: self.env.context.get('tz') or self.env.user.tz) +from . import models diff --git a/odoo/addons/test_convert/models.py b/odoo/addons/test_convert/models.py new file mode 100644 index 00000000000..e48ac2d1e7f --- /dev/null +++ b/odoo/addons/test_convert/models.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models, fields, api + + +class Usered(models.Model): + _name = 'test_convert.usered' + _description = "z test model ignore" + + name = fields.Char() + user_id = fields.Many2one('res.users', default=lambda self: self.env.user) + tz = fields.Char(default=lambda self: self.env.context.get('tz') or self.env.user.tz) + + @api.model + def model_method(self, *args, **kwargs): + return self, args, kwargs + + def method(self, *args, **kwargs): + return self, args, kwargs diff --git a/odoo/addons/test_convert/tests/test_convert.py b/odoo/addons/test_convert/tests/test_convert.py index e81526dd43c..709a5eeab10 100644 --- a/odoo/addons/test_convert/tests/test_convert.py +++ b/odoo/addons/test_convert/tests/test_convert.py @@ -7,7 +7,7 @@ import unittest from lxml.builder import E from odoo.tests import common -from odoo.tools.convert import _eval_xml +from odoo.tools.convert import xml_import, _eval_xml Field = E.field Value = E.value @@ -74,6 +74,118 @@ class TestEvalXML(common.TransactionCase): with self.assertRaises(IOError): self.eval_xml(Field('test_nofile.txt', type='file'), obj) + def test_function(self): + obj = xml_import(self.cr, 'test_convert', None, 'init') + + # pass args in eval + xml = E.function( + model="test_convert.usered", + name="model_method", + eval="[1, 2]", + ) + rec, args, kwargs = self.eval_xml(xml, obj) + self.assertEqual(rec.env.context, self.env.context) + self.assertEqual(rec.ids, []) + self.assertEqual(args, (1, 2)) + self.assertEqual(kwargs, {}) + + xml = E.function( + model="test_convert.usered", + name="method", + eval="[1, 2]", + ) + rec, args, kwargs = self.eval_xml(xml, obj) + self.assertEqual(rec.env.context, self.env.context) + self.assertEqual(rec.ids, [1]) + self.assertEqual(args, (2,)) + self.assertEqual(kwargs, {}) + + # pass args in child elements + xml = E.function( + E.value(eval="1"), E.value(eval="2"), + model="test_convert.usered", + name="model_method", + ) + rec, args, kwargs = self.eval_xml(xml, obj) + self.assertEqual(rec.env.context, self.env.context) + self.assertEqual(rec.ids, []) + self.assertEqual(args, (1, 2)) + self.assertEqual(kwargs, {}) + + xml = E.function( + E.value(eval="1"), E.value(eval="2"), + model="test_convert.usered", + name="method", + ) + rec, args, kwargs = self.eval_xml(xml, obj) + self.assertEqual(rec.env.context, self.env.context) + self.assertEqual(rec.ids, [1]) + self.assertEqual(args, (2,)) + self.assertEqual(kwargs, {}) + + def test_function_kwargs(self): + obj = xml_import(self.cr, 'test_convert', None, 'init') + + # pass args and kwargs in child elements + xml = E.function( + E.value(eval="1"), E.value(name="foo", eval="2"), + model="test_convert.usered", + name="model_method", + ) + rec, args, kwargs = self.eval_xml(xml, obj) + self.assertEqual(rec.env.context, self.env.context) + self.assertEqual(rec.ids, []) + self.assertEqual(args, (1,)) + self.assertEqual(kwargs, {'foo': 2}) + + xml = E.function( + E.value(eval="1"), E.value(name="foo", eval="2"), + model="test_convert.usered", + name="method", + ) + rec, args, kwargs = self.eval_xml(xml, obj) + self.assertEqual(rec.env.context, self.env.context) + self.assertEqual(rec.ids, [1]) + self.assertEqual(args, ()) + self.assertEqual(kwargs, {'foo': 2}) + + # pass args and context in kwargs + xml = E.function( + E.value(eval="1"), E.value(name="context", eval="{'foo': 2}"), + model="test_convert.usered", + name="model_method", + ) + rec, args, kwargs = self.eval_xml(xml, obj) + self.assertEqual(rec.env.context, {'foo': 2}) + self.assertEqual(rec.ids, []) + self.assertEqual(args, (1,)) + self.assertEqual(kwargs, {}) + + xml = E.function( + E.value(eval="1"), E.value(name="context", eval="{'foo': 2}"), + model="test_convert.usered", + name="method", + ) + rec, args, kwargs = self.eval_xml(xml, obj) + self.assertEqual(rec.env.context, {'foo': 2}) + self.assertEqual(rec.ids, [1]) + self.assertEqual(args, ()) + self.assertEqual(kwargs, {}) + + def test_function_function(self): + obj = xml_import(self.cr, 'test_convert', None, 'init') + + xml = E.function( + E.function(model="test_convert.usered", name="search", eval="[[]]"), + model="test_convert.usered", + name="method", + ) + rec, args, kwargs = self.eval_xml(xml, obj) + self.assertEqual(rec.env.context, {}) + self.assertEqual(rec.ids, []) + self.assertEqual(args, ()) + self.assertEqual(kwargs, {}) + @unittest.skip("not tested") def test_xml(self): pass diff --git a/odoo/import_xml.rng b/odoo/import_xml.rng index 953cac69e42..83324f379a9 100644 --- a/odoo/import_xml.rng +++ b/odoo/import_xml.rng @@ -23,6 +23,7 @@ <rng:define name="value"> <rng:element name="value"> + <rng:optional><rng:attribute name="name" /></rng:optional> <rng:optional><rng:attribute name="model" /></rng:optional> <rng:choice> <rng:attribute name="search" /> diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py index e677560979e..7a3ff444cce 100644 --- a/odoo/tools/convert.py +++ b/odoo/tools/convert.py @@ -177,32 +177,24 @@ def _eval_xml(self, node, env): return tuple(res) return res elif node.tag == "function": + model = env[node.get('model')] + method_name = node.get('name') + # determine arguments + args = [] + kwargs = {} a_eval = node.get('eval') if a_eval: self.idref['ref'] = self.id_get - # ensure the args are a list (sometimes folks eval a tuple which - # is inconvenient when trying to concatenate w/ a list) args = list(safe_eval(a_eval, self.idref)) - else: - args = [ - r for r in (_eval_xml(self, n, env) for n in node) - if r is not None - ] - - model = env[node.get('model')] - method_name = node.get('name') - method = getattr(model, method_name) - - # this mess is necessary to merge @context and a possible positional - # context parameter, as <function> works on the old API so ids and - # context are just args - ids, args = [], list(args) - if getattr(method, '_api', None) not in ('model', 'model_create'): - ids, args = args[:1], args[1:] - context, args, kwargs = api.split_context(method, args, {}) - kwargs['context'] = {**env.context, **(context or {})} - - return odoo.api.call_kw(model, method_name, ids + args, kwargs) + for child in node: + if child.tag == 'value' and child.get('name'): + kwargs[child.get('name')] = _eval_xml(self, child, env) + else: + args.append(_eval_xml(self, child, env)) + # merge current context with context in kwargs + kwargs['context'] = {**env.context, **kwargs.get('context', {})} + # invoke method + return odoo.api.call_kw(model, method_name, args, kwargs) elif node.tag == "test": return node.text |
