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/fields.py b/odoo/fields.py index 89d0bc813ea..9b0a5fea8af 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -310,6 +310,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 @@ -637,7 +638,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 2a0d43313c4..f47405d5a96 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -1630,31 +1630,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 @@ -2224,6 +2231,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, @@ -2340,7 +2348,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.