summaryrefslogtreecommitdiff
path: root/odoo/addons
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-09-20 14:16:48 +0000
committerChristophe Simonis <chs@odoo.com>2019-09-20 14:33:54 +0000
commit58a83d12228fbbd4e9dde542e133d264204ee0f3 (patch)
tree60aaf45e3281e88fddc58fea8fe75de0ad4e2f46 /odoo/addons
parentf6da4d57bcc8e19ae0bd6d571926706bee46e08f (diff)
parent4a1321bc99dd7d8d153aceb2d0076161ce28bcd7 (diff)
[MERGE] forward port branch saas-12.4 up to 4a1321bc99d
closes odoo/odoo#37127 Signed-off-by: Christophe Simonis <chs@odoo.com>
Diffstat (limited to 'odoo/addons')
-rw-r--r--odoo/addons/base/models/ir_mail_server.py2
-rw-r--r--odoo/addons/base/models/ir_qweb_fields.py6
-rw-r--r--odoo/addons/base/models/res_users.py37
-rw-r--r--odoo/addons/base/tests/test_ir_sequence_date_range.py2
-rw-r--r--odoo/addons/base/tests/test_user_has_group.py18
-rw-r--r--odoo/addons/base/views/ir_qweb_widget_templates.xml4
-rw-r--r--odoo/addons/base/views/res_partner_views.xml2
-rw-r--r--odoo/addons/test_testing_utilities/tests/test_methods.py6
8 files changed, 65 insertions, 12 deletions
diff --git a/odoo/addons/base/models/ir_mail_server.py b/odoo/addons/base/models/ir_mail_server.py
index ee8944083b6..195f899172d 100644
--- a/odoo/addons/base/models/ir_mail_server.py
+++ b/odoo/addons/base/models/ir_mail_server.py
@@ -126,7 +126,7 @@ def encode_rfc2822_address_header(header_text):
return formataddr((name, email))
except UnicodeEncodeError:
_logger.warning(_('Failed to encode the address %s\n'
- 'from mail header:\n%s') % addr, header_text)
+ 'from mail header:\n%s') % (addr, header_text))
return ""
addresses = getaddresses([pycompat.to_text(ustr(header_text))])
diff --git a/odoo/addons/base/models/ir_qweb_fields.py b/odoo/addons/base/models/ir_qweb_fields.py
index 8f64560203c..2cc77269e27 100644
--- a/odoo/addons/base/models/ir_qweb_fields.py
+++ b/odoo/addons/base/models/ir_qweb_fields.py
@@ -601,7 +601,7 @@ class BarcodeConverter(models.AbstractModel):
def get_available_options(self):
options = super(BarcodeConverter, self).get_available_options()
options.update(
- type=dict(type='string', string=_('Barcode type'), description=_('Barcode type, eg: UPCA, EAN13, Code128'), default_value='Code128'),
+ symbology=dict(type='string', string=_('Barcode symbology'), description=_('Barcode type, eg: UPCA, EAN13, Code128'), default_value='Code128'),
width=dict(type='integer', string=_('Width'), default_value=600),
height=dict(type='integer', string=_('Height'), default_value=100),
humanreadable=dict(type='integer', string=_('Human Readable'), default_value=0),
@@ -610,9 +610,9 @@ class BarcodeConverter(models.AbstractModel):
@api.model
def value_to_html(self, value, options=None):
- barcode_type = options.get('type', 'Code128')
+ barcode_symbology = options.get('symbology', 'Code128')
barcode = self.env['ir.actions.report'].barcode(
- barcode_type,
+ barcode_symbology,
value,
**{key: value for key, value in options.items() if key in ['width', 'height', 'humanreadable']})
return u'<img src="data:png;base64,%s">' % base64.b64encode(barcode).decode('ascii')
diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py
index ea8a05811f3..66b0b2f3e49 100644
--- a/odoo/addons/base/models/res_users.py
+++ b/odoo/addons/base/models/res_users.py
@@ -400,10 +400,42 @@ class Users(models.Model):
@api.constrains('groups_id')
def _check_one_user_type(self):
- for user in self:
- if len(user.groups_id.filtered(lambda x: x.category_id.xml_id == 'base.module_category_user_type')) > 1:
+ """We check that no users are both portal and users (same with public).
+ This could typically happen because of implied groups.
+ """
+ user_types_category = self.env.ref('base.module_category_user_type', raise_if_not_found=False)
+ user_types_groups = self.env['res.groups'].search(
+ [('category_id', '=', user_types_category.id)]) if user_types_category else False
+ if user_types_groups: # needed at install
+ if self._has_multiple_groups(user_types_groups.ids):
raise ValidationError(_('The user cannot have more than one user types.'))
+ def _has_multiple_groups(self, group_ids):
+ """The method is not fast if the list of ids is very long;
+ so we rather check all users than limit to the size of the group
+ :param group_ids: list of group ids
+ :return: boolean: is there at least a user in at least 2 of the provided groups
+ """
+ if group_ids:
+ args = [tuple(group_ids)]
+ if len(self.ids) == 1:
+ where_clause = "AND r.uid = %s"
+ args.append(self.id)
+ else:
+ where_clause = "" # default; we check ALL users (actually pretty efficient)
+ query = """
+ SELECT 1 FROM res_groups_users_rel WHERE EXISTS(
+ SELECT r.uid
+ FROM res_groups_users_rel r
+ WHERE r.gid IN %s""" + where_clause + """
+ GROUP BY r.uid HAVING COUNT(r.gid) > 1
+ )
+ """
+ self.env.cr.execute(query, args)
+ return bool(self.env.cr.fetchall())
+ else:
+ return False
+
def toggle_active(self):
for user in self:
if not user.active and not user.partner_id.active:
@@ -939,6 +971,7 @@ class GroupsImplied(models.Model):
JOIN group_imply i ON (r.gid = i.hid)
WHERE i.gid = %(gid)s
""", dict(gid=group.id))
+ self._check_one_user_type()
return res
class UsersImplied(models.Model):
diff --git a/odoo/addons/base/tests/test_ir_sequence_date_range.py b/odoo/addons/base/tests/test_ir_sequence_date_range.py
index 08729f3a072..43e218f1189 100644
--- a/odoo/addons/base/tests/test_ir_sequence_date_range.py
+++ b/odoo/addons/base/tests/test_ir_sequence_date_range.py
@@ -24,7 +24,7 @@ class TestIrSequenceDateRangeStandard(SingleTransactionCase):
year = date.today().year - 1
january = lambda d: date(year, 1, d)
- seq16 = self.env['ir.sequence'].with_context({'ir_sequence_date': january(16)})
+ seq16 = self.env['ir.sequence'].with_context(ir_sequence_date=january(16))
n = seq16.next_by_code('test_sequence_date_range')
self.assertEqual(n, '1')
n = seq16.next_by_code('test_sequence_date_range')
diff --git a/odoo/addons/base/tests/test_user_has_group.py b/odoo/addons/base/tests/test_user_has_group.py
index 61f6efaecfb..4f5b2bc61dd 100644
--- a/odoo/addons/base/tests/test_user_has_group.py
+++ b/odoo/addons/base/tests/test_user_has_group.py
@@ -143,3 +143,21 @@ class TestHasGroup(TransactionCase):
})
with self.assertRaises(ValidationError):
self.grp_internal.users = [(4, test_user.id)]
+
+ def test_two_user_types_implied_groups(self):
+ """Contrarily to test_two_user_types, we simply add an implied_id to a group.
+ This will trigger the addition of the relevant users to the relevant groups;
+ if, say, this was done in SQL and thus bypassing the ORM, it would bypass the constraints
+ and thus give us a case uncovered by the aforementioned test.
+ """
+ grp_test = self.env["res.groups"].create(
+ {"name": "test", "implied_ids": [(6, 0, [self.grp_internal.id])]})
+
+ test_user = self.env['res.users'].create({
+ 'login': 'test_user_portal',
+ 'name': "Test User with one user types",
+ 'groups_id': [(6, 0, [grp_test.id])]
+ })
+
+ with self.assertRaises(ValidationError):
+ grp_test.write({'implied_ids': [(4, self.grp_portal.id)]})
diff --git a/odoo/addons/base/views/ir_qweb_widget_templates.xml b/odoo/addons/base/views/ir_qweb_widget_templates.xml
index 47bf04a62ff..4f141cadb71 100644
--- a/odoo/addons/base/views/ir_qweb_widget_templates.xml
+++ b/odoo/addons/base/views/ir_qweb_widget_templates.xml
@@ -13,7 +13,7 @@
</div>
</template>
<template id="contact">
- <address t-ignore="true" class="d-inline-block mb-0" itemscope="itemscope" itemtype="http://schema.org/Organization">
+ <address t-ignore="true" class="mb-0" itemscope="itemscope" itemtype="http://schema.org/Organization">
<div t-if="not (('name' in fields) or (address and 'address' in fields) or (city and 'city' in fields) or (mobile and 'mobile' in fields) or (website and 'website' in fields) or (email and 'email' in fields))" class="css_non_editable_mode_hidden">
--<span class="text-muted" t-esc="name"/>--
</div>
@@ -23,7 +23,7 @@
<div itemprop="address" itemscope="itemscope" itemtype="http://schema.org/PostalAddress">
<div t-if="address and 'address' in fields" class="d-flex align-items-baseline">
<i t-if="not options.get('no_marker')" class="fa fa-map-marker fa-fw" role="img" aria-label="Address" title="Address"/>
- <span itemprop="streetAddress" t-raw="address.replace('\n', options.get('no_tag_br') and ', ' or ('&lt;br/&gt;%s' % ('' if options.get('no_marker') else '')))"/>
+ <div class="w-100" itemprop="streetAddress" t-raw="address.replace('\n', options.get('no_tag_br') and ', ' or ('&lt;br/&gt;%s' % ('' if options.get('no_marker') else '')))"/>
</div>
<div t-if="city and 'city' in fields" class="d-flex align-items-baseline">
<i t-if="not options.get('no_marker')" class="fa fa-map-marker fa-fw" role="img" aria-label="Address" title="Address"/>
diff --git a/odoo/addons/base/views/res_partner_views.xml b/odoo/addons/base/views/res_partner_views.xml
index 96b2f0dcb3c..aa8e65f5508 100644
--- a/odoo/addons/base/views/res_partner_views.xml
+++ b/odoo/addons/base/views/res_partner_views.xml
@@ -524,7 +524,7 @@
<img class="o_kanban_image_inner_pic" t-if="record.parent_id.raw_value" t-att-alt="record.parent_id.value" t-att-src="kanban_image('res.partner', 'image_128', record.parent_id.raw_value)"/>
</div>
</t>
- <t t-else="">
+ <t t-elif="record.image_128.raw_value">
<t t-set="placeholder" t-value="'/base/static/img/company_image.png'"/>
<div class="o_kanban_image_fill_left o_kanban_image_full" t-attf-style="background-image: url(#{kanban_image('res.partner', 'image_128', record.id.raw_value, placeholder)})" role="img"/>
</t>
diff --git a/odoo/addons/test_testing_utilities/tests/test_methods.py b/odoo/addons/test_testing_utilities/tests/test_methods.py
index 031d3a5e2ec..2a783aa2166 100644
--- a/odoo/addons/test_testing_utilities/tests/test_methods.py
+++ b/odoo/addons/test_testing_utilities/tests/test_methods.py
@@ -11,9 +11,11 @@ class TestBasic(common.TransactionCase):
Y3 = {'f1': "Y", 'f2': 3}
records = self.env['test_testing_utilities.a'].create([X1, Y2])
- # match in any order
self.assertRecordValues(records, [X1, Y2])
- self.assertRecordValues(records, [Y2, X1])
+
+ with self.assertRaises(AssertionError):
+ # order should match
+ self.assertRecordValues(records, [Y2, X1])
# fail if wrong size
with self.assertRaises(AssertionError):