Before this commit, calling read_group on a model and grouping by a
selection field would return the groups in alphabetical order, meaning
that if your selection field's options were declared as:
('z', 'Z'), ('a', 'A')
read_group would return first group 'a' and then group 'z', instead of
groups 'z' and then 'a' which some might expect.
With this commit, it is now possible to set a fields.Selection
group_expand attribute to `True` when declaring it, which will use a
default group_expand implementation specific to Selection fields, this
means that when grouping by a Selection field with `group_expand=True`
it will always return the groups in the definition order of the
selection options.
We achieve this by leveraging the group_expand field attribute which was
designed for changing the groups returned by read_group.
Since this attribute was thought only to be implemented on a
Model-by-Model basis and here we need to use it as a generic function
for all Selection fields (explicit group_expand declarations have higher
precedence), the generic method has been implemented inside
fields.Selection and takes an extra records parameter which holds a
reference to the recordset/model on which read_group was called. This
extra parameter only applies to field implementations of group_expand
and in this case is what allows this specific feature to work with
dynamic Selection fields (function as options).
A side-effect of this implementation is that a read_group call that
groups by a Selection field with `group_expand=True` that uses the
default group_expand will always return all possible groups, even
empty ones.
Task-ID 2635052
closes odoo/odoo#75856
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
104 lines
2.8 KiB
Python
104 lines
2.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo import fields, models
|
|
|
|
|
|
class GroupOnDate(models.Model):
|
|
_name = 'test_read_group.on_date'
|
|
_description = 'Group Test Read On Date'
|
|
|
|
date = fields.Date("Date")
|
|
value = fields.Integer("Value")
|
|
|
|
|
|
class BooleanAggregate(models.Model):
|
|
_name = 'test_read_group.aggregate.boolean'
|
|
_description = 'Group Test Read Boolean Aggregate'
|
|
_order = 'key DESC'
|
|
|
|
key = fields.Integer()
|
|
bool_and = fields.Boolean(default=False, group_operator='bool_and')
|
|
bool_or = fields.Boolean(default=False, group_operator='bool_or')
|
|
bool_array = fields.Boolean(default=False, group_operator='array_agg')
|
|
|
|
|
|
class Aggregate(models.Model):
|
|
_name = 'test_read_group.aggregate'
|
|
_order = 'id'
|
|
_description = 'Group Test Aggregate'
|
|
|
|
key = fields.Integer()
|
|
value = fields.Integer("Value")
|
|
partner_id = fields.Many2one('res.partner')
|
|
|
|
|
|
# we use a selection that is in reverse lexical order, in order to check the
|
|
# possible reordering made by read_group on selection fields
|
|
SELECTION = [('c', "C"), ('b', "B"), ('a', "A")]
|
|
|
|
|
|
class GroupOnSelection(models.Model):
|
|
_name = 'test_read_group.on_selection'
|
|
_description = 'Group Test Read On Selection'
|
|
|
|
state = fields.Selection([('a', "A"), ('b', "B")], group_expand='_expand_states')
|
|
static_expand = fields.Selection(SELECTION, group_expand=True)
|
|
dynamic_expand = fields.Selection(lambda self: SELECTION, group_expand=True)
|
|
no_expand = fields.Selection(SELECTION)
|
|
value = fields.Integer()
|
|
|
|
def _expand_states(self, states, domain, order):
|
|
# return all possible states, in order
|
|
return [key for key, val in type(self).state.selection]
|
|
|
|
|
|
class FillTemporal(models.Model):
|
|
_name = 'test_read_group.fill_temporal'
|
|
_description = 'Group Test Fill Temporal'
|
|
|
|
date = fields.Date()
|
|
datetime = fields.Datetime()
|
|
value = fields.Integer()
|
|
|
|
|
|
class Order(models.Model):
|
|
_name = 'test_read_group.order'
|
|
_description = 'Sales order'
|
|
|
|
line_ids = fields.One2many('test_read_group.order.line', 'order_id')
|
|
|
|
|
|
class OrderLine(models.Model):
|
|
_name = 'test_read_group.order.line'
|
|
_description = 'Sales order line'
|
|
|
|
order_id = fields.Many2one('test_read_group.order', ondelete='cascade')
|
|
value = fields.Integer()
|
|
|
|
|
|
class User(models.Model):
|
|
_name = 'test_read_group.user'
|
|
_description = "User"
|
|
|
|
name = fields.Char(required=True)
|
|
task_ids = fields.Many2many(
|
|
'test_read_group.task',
|
|
'test_read_group_task_user_rel',
|
|
'user_id',
|
|
'task_id',
|
|
string="Tasks",
|
|
)
|
|
|
|
|
|
class Task(models.Model):
|
|
_name = 'test_read_group.task'
|
|
_description = "Project task"
|
|
|
|
name = fields.Char(required=True)
|
|
user_ids = fields.Many2many(
|
|
'test_read_group.user',
|
|
'test_read_group_task_user_rel',
|
|
'task_id',
|
|
'user_id',
|
|
string="Collaborators",
|
|
)
|