From 87b42ad9a887faacbbefcab9dd0703a5c51ce28b Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 18 Apr 2018 10:48:40 +0200 Subject: [PATCH 1/2] [FIX] models: make group by date and order by date work together The issue occurs when `read_group` is called with a date/datetime field to group and order on, and the group_by is qualified, such as: model.read_group(..., groupby=['date:week'], orderby='date') The ORDER BY clause in the query should use the same term as the GROUP BY clause for the corresponding field. OPW 1834148 --- odoo/addons/base/tests/test_orm.py | 19 +++++++++++++++++++ odoo/models.py | 17 ++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/odoo/addons/base/tests/test_orm.py b/odoo/addons/base/tests/test_orm.py index ef586218a0d..7f39097b2dd 100644 --- a/odoo/addons/base/tests/test_orm.py +++ b/odoo/addons/base/tests/test_orm.py @@ -163,6 +163,25 @@ class TestORM(TransactionCase): ['date:month', 'date:day'], lazy=False) self.assertEqual(len(res), len(partner_ids)) + # combine groupby and orderby + months = ['February 2013', 'January 2013', 'December 2012', 'November 2012'] + res = partners.read_group([('id', 'in', partner_ids)], ['date'], + groupby=['date:month'], orderby='date:month DESC') + self.assertEqual([item['date:month'] for item in res], months) + + # order by date should reorder by date:month + res = partners.read_group([('id', 'in', partner_ids)], ['date'], + groupby=['date:month'], orderby='date DESC') + self.assertEqual([item['date:month'] for item in res], months) + + # order by date should reorder by date:day + days = ['11 Feb 2013', '28 Jan 2013', '14 Jan 2013', '07 Jan 2013', + '31 Dec 2012', '17 Dec 2012', '19 Nov 2012'] + res = partners.read_group([('id', 'in', partner_ids)], ['date'], + groupby=['date:month', 'date:day'], + orderby='date DESC', lazy=False) + self.assertEqual([item['date:day'] for item in res], days) + def test_write_duplicate(self): p1 = self.env['res.partner'].create({'name': 'W'}) (p1 + p1).write({'name': 'X'}) diff --git a/odoo/models.py b/odoo/models.py index a47fd56b0d7..f5c8a84595d 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -1735,31 +1735,38 @@ class BaseModel(object): """ orderby_terms = [] groupby_terms = [gb['qualified_field'] for gb in annotated_groupbys] - groupby_fields = [gb['groupby'] for gb in annotated_groupbys] if not orderby: return groupby_terms, orderby_terms self._check_qorder(orderby) + + # when a field is grouped as 'foo:bar', both orderby='foo' and + # orderby='foo:bar' generate the clause 'ORDER BY "foo:bar"' + groupby_fields = { + gb[key]: gb['groupby'] + for gb in annotated_groupbys + for key in ('field', 'groupby') + } for order_part in orderby.split(','): order_split = order_part.split() order_field = order_split[0] if order_field == 'id' or order_field in groupby_fields: - if self._fields[order_field.split(':')[0]].type == 'many2one': order_clause = self._generate_order_by(order_part, query).replace('ORDER BY ', '') if order_clause: orderby_terms.append(order_clause) groupby_terms += [order_term.split()[0] for order_term in order_clause.split(',')] else: - order = '"%s" %s' % (order_field, '' if len(order_split) == 1 else order_split[1]) - orderby_terms.append(order) + order_split[0] = '"%s"' % groupby_fields.get(order_field, order_field) + orderby_terms.append(' '.join(order_split)) elif order_field in aggregated_fields: - order_split[0] = '"' + order_field + '"' + order_split[0] = '"%s"' % order_field orderby_terms.append(' '.join(order_split)) else: # Cannot order by a field that will not appear in the results (needs to be grouped or aggregated) _logger.warn('%s: read_group order by `%s` ignored, cannot sort on empty columns (not grouped/aggregated)', self._name, order_part) + return groupby_terms, orderby_terms @api.model From 23431389c36e57bfce99afb97abfca6a062cfc74 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Tue, 17 Apr 2018 16:57:39 +0200 Subject: [PATCH 2/2] [FIX] models: bad setup of inherited custom fields Assume a custom field F is defined on model 'res.partner'. The setup of F may silently fail because of missing stuff. In that situation, setting up the field inherited from F on model 'res.users' should also silently fail. To reproduce the bug, install Invoicing, create a related custom field F on 'res.partner' with 'property_account_position_id.active', and install another module. Setting up F after loading module 'base' will fail because the field 'property_account_position_id' does not exist yet. The error is not caught by the inheritance of F on model 'res.users', and the installation crashes. OPW 1835872 --- odoo/fields.py | 3 ++- odoo/models.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/odoo/fields.py b/odoo/fields.py index 60043915925..b472e35658b 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -320,6 +320,7 @@ class Field(object): 'automatic': False, # whether the field is automatically created ("magic" field) 'inherited': False, # whether the field is inherited (_inherits) + 'inherited_field': None, # the corresponding inherited field 'name': None, # name of the field 'model_name': None, # name of the model of this field @@ -647,7 +648,7 @@ class Field(object): @property def base_field(self): """ Return the base field of an inherited field, or ``self``. """ - return self.related_field.base_field if self.inherited else self + return self.inherited_field.base_field if self.inherited_field else self # # Company-dependent fields diff --git a/odoo/models.py b/odoo/models.py index f5c8a84595d..d04e6642254 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -2734,6 +2734,7 @@ class BaseModel(object): # - copy inherited fields iff their original field is copied fields[name] = field.new( inherited=True, + inherited_field=field, related=(parent_field, name), related_sudo=False, copy=field.copy, @@ -2850,7 +2851,7 @@ class BaseModel(object): try: field.setup_full(self) except Exception: - if partial and field.manual: + if partial and field.base_field.manual: # Something goes wrong when setup a manual field. # This can happen with related fields using another manual many2one field # that hasn't been loaded because the comodel does not exist yet.