summaryrefslogtreecommitdiff
path: root/odoo
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-03-06 10:59:32 +0100
committerChristophe Simonis <chs@odoo.com>2019-03-06 10:59:32 +0100
commitafe013330295b5f069a0df8529d1f1f0d12f2b3f (patch)
treee9e39304f0e797c0cd8b4314c173948e90181a90 /odoo
parentb5885f0cb02ba6853e17eb93009b1ebad2ff8d35 (diff)
parent3e54704e669441e655b1fe19ee0fa0646cdbf8d5 (diff)
[MERGE] forward port branch saas-11.3 up to 3e54704e669
Diffstat (limited to 'odoo')
-rw-r--r--odoo/addons/base/models/ir_model.py3
-rw-r--r--odoo/addons/base/models/ir_rule.py2
-rw-r--r--odoo/addons/base/models/qweb.py57
-rw-r--r--odoo/addons/base/tests/test_expression.py30
-rw-r--r--odoo/addons/base/tests/test_qweb.py41
-rw-r--r--odoo/addons/base/tests/test_views.py36
-rw-r--r--odoo/fields.py1
-rw-r--r--odoo/models.py1
-rw-r--r--odoo/osv/expression.py2
9 files changed, 151 insertions, 22 deletions
diff --git a/odoo/addons/base/models/ir_model.py b/odoo/addons/base/models/ir_model.py
index 1bbf53794a6..4a59c5d4249 100644
--- a/odoo/addons/base/models/ir_model.py
+++ b/odoo/addons/base/models/ir_model.py
@@ -199,6 +199,9 @@ class IrModel(models.Model):
# prevent screwing up fields that depend on these models' fields
model.field_id._prepare_update()
+ # delete fields whose comodel is being removed
+ self.env['ir.model.fields'].search([('relation', 'in', self.mapped('model'))]).unlink()
+
self._drop_table()
res = super(IrModel, self).unlink()
diff --git a/odoo/addons/base/models/ir_rule.py b/odoo/addons/base/models/ir_rule.py
index 90869ef45ac..9f63a415892 100644
--- a/odoo/addons/base/models/ir_rule.py
+++ b/odoo/addons/base/models/ir_rule.py
@@ -106,6 +106,8 @@ class IrRule(models.Model):
group_domains.append(dom)
# combine global domains and group domains
+ if not group_domains:
+ return expression.AND(global_domains)
return expression.AND(global_domains + [expression.OR(group_domains)])
@api.model
diff --git a/odoo/addons/base/models/qweb.py b/odoo/addons/base/models/qweb.py
index 51693c55cb1..de5d3cf9e2b 100644
--- a/odoo/addons/base/models/qweb.py
+++ b/odoo/addons/base/models/qweb.py
@@ -31,6 +31,8 @@ try:
except ImportError:
astor = None
+from odoo.tools.parse_version import parse_version
+
unsafe_eval = eval
_logger = logging.getLogger(__name__)
@@ -176,7 +178,7 @@ class QWebException(Exception):
return str(self)
# Avoid DeprecationWarning while still remaining compatible with werkzeug pre-0.9
-escape = (lambda text: _escape(text, quote=True)) if getattr(werkzeug, '__version__', '0.0') < '0.9.0' else _escape
+escape = (lambda text: _escape(text, quote=True)) if parse_version(getattr(werkzeug, '__version__', '0.0')) < parse_version('0.9.0') else _escape
def foreach_iterator(base_ctx, enum, name):
ctx = base_ctx.copy()
@@ -1486,7 +1488,7 @@ class QWeb(object):
)
if call_options:
- # update this dict with the content of `t-call-options`
+ # update this dict with the content of `t-call-options`
content.extend([
# options_.update(template options)
ast.Expr(ast.Call(
@@ -1497,7 +1499,56 @@ class QWeb(object):
),
args=[self._compile_expr(call_options)],
keywords=[], starargs=None, kwargs=None
- ))
+ )),
+
+ # if options.get('lang') != options_.get('lang'):
+ # self = self.with_context(lang=options.get('lang'))
+ ast.If(
+ test=ast.Compare(
+ left=ast.Call(
+ func=ast.Attribute(
+ value=ast.Name(id='options', ctx=ast.Load()),
+ attr='get',
+ ctx=ast.Load()
+ ),
+ args=[ast.Str("lang")], keywords=[],
+ starargs=None, kwargs=None
+ ),
+ ops=[ast.NotEq()],
+ comparators=[ast.Call(
+ func=ast.Attribute(
+ value=ast.Name(id=name_options, ctx=ast.Load()),
+ attr='get',
+ ctx=ast.Load()
+ ),
+ args=[ast.Str("lang")], keywords=[],
+ starargs=None, kwargs=None
+ )]
+ ),
+ body=[
+ ast.Assign(
+ targets=[ast.Name(id='self', ctx=ast.Store())],
+ value=ast.Call(
+ func=ast.Attribute(
+ value=ast.Name(id='self', ctx=ast.Load()),
+ attr='with_context',
+ ctx=ast.Load()
+ ),
+ args=[],
+ keywords=[ast.keyword('lang', ast.Call(
+ func=ast.Attribute(
+ value=ast.Name(id=name_options, ctx=ast.Load()),
+ attr='get',
+ ctx=ast.Load()
+ ),
+ args=[ast.Str("lang")], keywords=[],
+ starargs=None, kwargs=None
+ ))],
+ starargs=None, kwargs=None
+ )
+ )],
+ orelse=[],
+ )
])
if nsmap:
diff --git a/odoo/addons/base/tests/test_expression.py b/odoo/addons/base/tests/test_expression.py
index 9f628054f02..b40035dadd6 100644
--- a/odoo/addons/base/tests/test_expression.py
+++ b/odoo/addons/base/tests/test_expression.py
@@ -640,6 +640,36 @@ class TestExpression(TransactionCase):
'&', ('foo', '=', 2), ('bar', '=', 2)]
self.assertEqual(expression.OR([d1, d2]), expected)
+ def test_proper_combine_unit_leaves(self):
+ # test that unit leaves (TRUE_LEAF, FALSE_LEAF) are properly handled in specific cases
+ false = expression.FALSE_DOMAIN
+ true = expression.TRUE_DOMAIN
+ normal = [('foo', '=', 'bar')]
+ # OR with single FALSE_LEAF
+ expr = expression.OR([false])
+ self.assertEqual(expr, false)
+ # OR with multiple FALSE_LEAF
+ expr = expression.OR([false, false])
+ self.assertEqual(expr, false)
+ # OR with FALSE_LEAF and a normal leaf
+ expr = expression.OR([false, normal])
+ self.assertEqual(expr, normal)
+ # OR with AND of single TRUE_LEAF and normal leaf
+ expr = expression.OR([expression.AND([true]), normal])
+ self.assertEqual(expr, true)
+ # AND with single TRUE_LEAF
+ expr = expression.AND([true])
+ self.assertEqual(expr, true)
+ # AND with multiple TRUE_LEAF
+ expr = expression.AND([true, true])
+ self.assertEqual(expr, true)
+ # AND with TRUE_LEAF and normal leaves
+ expr = expression.AND([true, normal])
+ self.assertEqual(expr, normal)
+ # AND with OR with single FALSE_LEAF and normal leaf
+ expr = expression.AND([expression.OR([false]), normal])
+ self.assertEqual(expr, false)
+
class TestAutoJoin(TransactionCase):
diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py
index 2a01fa1ca44..d8ce5e48f68 100644
--- a/odoo/addons/base/tests/test_qweb.py
+++ b/odoo/addons/base/tests/test_qweb.py
@@ -501,6 +501,47 @@ class TestQWebNS(TransactionCase):
with self.assertRaises(QWebException, msg=error_msg):
view1.render()
+ def test_render_t_call_propagates_t_lang(self):
+ current_lang = 'en_US'
+ other_lang = 'fr_FR'
+
+ self.env['res.lang'].load_lang(lang=other_lang)
+
+ self.env['res.lang'].search([('code', '=', other_lang)], limit=1).write({
+ 'active': True,
+ 'decimal_point': '*',
+ 'thousands_sep': '/'
+ })
+
+ view1 = self.env['ir.ui.view'].create({
+ 'name': "callee",
+ 'type': 'qweb',
+ 'arch': u"""
+ <t t-name="base.callee">
+ <t t-esc="9000000.00" t-options="{'widget': 'float', 'precision': 2}" />
+ </t>
+ """
+ })
+ self.env['ir.model.data'].create({
+ 'name': 'callee',
+ 'model': 'ir.ui.view',
+ 'module': 'base',
+ 'res_id': view1.id,
+ })
+
+ view2 = self.env['ir.ui.view'].create({
+ 'name': "calling",
+ 'type': 'qweb',
+ 'arch': u"""
+ <t t-name="base.calling">
+ <t t-call="base.callee" t-lang="'%s'" />
+ </t>
+ """ % other_lang
+ })
+
+ rendered = view2.with_context(lang=current_lang).render().strip()
+ self.assertEqual(rendered, b'9/000/000*00')
+
from copy import deepcopy
class FileSystemLoader(object):
diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py
index 7b8deb8ea33..33ac7035488 100644
--- a/odoo/addons/base/tests/test_views.py
+++ b/odoo/addons/base/tests/test_views.py
@@ -1107,7 +1107,7 @@ class TestViews(ViewCase):
# implemeted elsewhere...
modifiers_tests()
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_invalid_field(self):
with self.assertRaises(ValidationError):
self.View.create({
@@ -1121,7 +1121,7 @@ class TestViews(ViewCase):
""",
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_invalid_subfield(self):
with self.assertRaises(ValidationError):
self.View.create({
@@ -1140,7 +1140,7 @@ class TestViews(ViewCase):
""",
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_context_in_view(self):
arch = """
<form string="View">
@@ -1160,7 +1160,7 @@ class TestViews(ViewCase):
'arch': arch % '',
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_context_in_subview(self):
arch = """
<form string="View">
@@ -1192,7 +1192,7 @@ class TestViews(ViewCase):
'arch': arch % ('<field name="model"/>', ''),
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_context_in_subview_with_parent(self):
arch = """
<form string="View">
@@ -1223,7 +1223,7 @@ class TestViews(ViewCase):
'arch': arch % ('', '<field name="model"/>'),
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_context_in_subsubview_with_parent(self):
arch = """
<form string="View">
@@ -1265,7 +1265,7 @@ class TestViews(ViewCase):
'arch': arch % ('', '', '<field name="model"/>'),
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_domain_in_view(self):
arch = """
<form string="View">
@@ -1285,7 +1285,7 @@ class TestViews(ViewCase):
'arch': arch % '',
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_domain_in_subview(self):
arch = """
<form string="View">
@@ -1316,7 +1316,7 @@ class TestViews(ViewCase):
'arch': arch % ('<field name="model"/>', ''),
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_domain_in_subview_with_parent(self):
arch = """
<form string="View">
@@ -1347,7 +1347,7 @@ class TestViews(ViewCase):
'arch': arch % ('', '<field name="model"/>'),
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_domain_on_field_in_view(self):
field = self.env['ir.ui.view']._fields['inherit_id']
self.patch(field, 'domain', "[('model', '=', model)]")
@@ -1370,7 +1370,7 @@ class TestViews(ViewCase):
'arch': arch % '',
})
- @mute_logger('odoo.addons.base.ir.ir_ui_view')
+ @mute_logger('odoo.addons.base.ir.ir_ui_view', 'odoo.models')
def test_domain_on_field_in_subview(self):
field = self.env['ir.ui.view']._fields['inherit_id']
self.patch(field, 'domain', "[('model', '=', model)]")
@@ -1404,7 +1404,7 @@ class TestViews(ViewCase):
'arch': arch % ('<field name="model"/>', ''),
})
- @mute_logger('odoo.addons.base.ir.ir_ui_view')
+ @mute_logger('odoo.addons.base.ir.ir_ui_view', 'odoo.models')
def test_domain_on_field_in_subview_with_parent(self):
field = self.env['ir.ui.view']._fields['inherit_id']
self.patch(field, 'domain', "[('model', '=', parent.model)]")
@@ -1438,7 +1438,7 @@ class TestViews(ViewCase):
'arch': arch % ('', '<field name="model"/>'),
})
- @mute_logger('odoo.addons.base.ir.ir_ui_view')
+ @mute_logger('odoo.addons.base.ir.ir_ui_view', 'odoo.models')
def test_domain_on_field_in_noneditable_subview(self):
field = self.env['ir.ui.view']._fields['inherit_id']
self.patch(field, 'domain', "[('model', '=', model)]")
@@ -1466,7 +1466,7 @@ class TestViews(ViewCase):
'arch': arch % ' editable="bottom"',
})
- @mute_logger('odoo.addons.base.ir.ir_ui_view')
+ @mute_logger('odoo.addons.base.ir.ir_ui_view', 'odoo.models')
def test_domain_on_readonly_field_in_view(self):
field = self.env['ir.ui.view']._fields['inherit_id']
self.patch(field, 'domain', "[('model', '=', model)]")
@@ -1496,7 +1496,7 @@ class TestViews(ViewCase):
'arch': arch,
})
- @mute_logger('odoo.addons.base.ir.ir_ui_view')
+ @mute_logger('odoo.addons.base.ir.ir_ui_view', 'odoo.models')
def test_domain_on_readonly_field_in_subview(self):
field = self.env['ir.ui.view']._fields['inherit_id']
self.patch(field, 'domain', "[('model', '=', model)]")
@@ -1524,7 +1524,7 @@ class TestViews(ViewCase):
'arch': arch % '',
})
- @mute_logger('odoo.addons.base.ir.ir_ui_view')
+ @mute_logger('odoo.addons.base.ir.ir_ui_view', 'odoo.models')
def test_attrs_field(self):
arch = """
<form string="View">
@@ -1545,7 +1545,7 @@ class TestViews(ViewCase):
'arch': arch % '',
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_attrs_subfield(self):
arch = """
<form string="View">
@@ -1577,7 +1577,7 @@ class TestViews(ViewCase):
'arch': arch % ('<field name="model"/>', ''),
})
- @mute_logger('odoo.addons.base.models.ir_ui_view')
+ @mute_logger('odoo.addons.base.models.ir_ui_view', 'odoo.models')
def test_attrs_subfield_with_parent(self):
arch = """
<form string="View">
diff --git a/odoo/fields.py b/odoo/fields.py
index 1efc86de888..b02564dd908 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -161,6 +161,7 @@ class Field(MetaField('DummyField', (object,), {})):
:param compute_sudo: whether the field should be recomputed as superuser
to bypass access rights (boolean, by default ``False``)
+ Note that this has no effects on non-stored computed fields
The methods given for ``compute``, ``inverse`` and ``search`` are model
methods. Their signature is shown in the following example::
diff --git a/odoo/models.py b/odoo/models.py
index e49f98ee0d8..439b8423f09 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -1109,6 +1109,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
except ValidationError as e:
raise
except Exception as e:
+ _logger.exception('Exception while validating constraint')
raise ValidationError("%s\n\n%s" % (_("Error while validating constraint"), tools.ustr(e)))
@api.model
diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py
index f5518fead94..170c2b971e8 100644
--- a/odoo/osv/expression.py
+++ b/odoo/osv/expression.py
@@ -262,7 +262,7 @@ def combine(operator, unit, zero, domains):
result += normalize_domain(domain)
count += 1
result = [operator] * (count - 1) + result
- return result
+ return result or unit
def AND(domains):