1. Objective
- We are in a Kanban view, and we group by a "date/datetime" field.
- In order to "quick create" a record in a group, or to "drag & drop" a
record between 2 groups, we need a default value for this date field.
- In this case, a group represents a "range" of dates. A default value could
be the last date of this range.
- Prior to this commit, the view had only access to a display string for this
date range. We want to have access to the concrete bounds (start/end dates)
- Since some date/datetime fields have backend constraints, it would be
difficult to generate a compliant global default value. As such, the use of
the default value should be disabled by default and activated on a field by
field basis.
2. Usage
- Use the last day (for dates), or second (for datetimes) of the range to set
a default value in kanban "quick create" and "drag & drop"
- Use the end of the range of the last group from a read_group to be able to
request the next group (chronological order) in subsequent read_group calls
3. What are the changes in this commit
- read_group from the "core" "models.py", with the added __range for
date(time) fields, a dictionary for each group. The keys are the field
names and the values are a dictionary with the following keys: value:
- from: starting date(time) of the range (inclusive)
- to: ending date(time) of the range (exclusive)
- XML changes:
- with a new xml attribute on <field> tag allow_group_range_value (for the
kanban view):
- we allow (or disallow) supported non-readonly fields to be:
- draggable
- quick created
- this attribute can be used only on date(time) fields, and if not set,
the default behavior is false
- the naming is subject to contention because it relates to
different features. The relation comes from the constraint:
To perform a drag&drop or a quickCreate, we must be able to get the
value from the group containing the record.
- JS changes:
- we add "group.range" after a read_group for date fields, which is a
dictionary: {field_name: {from, to}}, for each date(time) groupby field
- since date(time) fields can use the format "date_field:granularity" when
used in a groupby, we have to properly split out the granularity to ensure
compatibility with the code previously in place (drag&drop procedures)
- update mock_server and sample_server to make use of the date range.
Adding support for datetime grouping to both mock and sample servers, for
tests and previews.
- the default value for kanban drag&drop and quickCreate features is the
last day/second of the range for date/datetime fields
4. Why can't this range be computed from the original display value with
moment.js
The Babel python library that we use for date(time) formatting (2.6.0) is kept
at the same version as the package in stable Debian Linux. This version has
some issues with displaying weeks consistently around the new year in certain
locales.
We cannot reverse compute a date(time) label with moment.js to get a range since
nothing guarantees that the range will be the same one that Babel used to
output it.
5. read_group return format discussion
Prior to this commit, the format of the value for the groupBy field was
either :
- String : used as a display value for the group.
Most notably, for date and datetime, this value cannot be used as a field
value in most cases. It would be more practical to also return the date
range along with the display value, so that Drag&Drop and QuickCreate
functionalities can be properly enabled in views
example :
"March 2021" has the range ['&', (field, '>=', 2021-03-01),
(field, '<', 2021-04-01)]
This information is lost at the end of the read_group.
- Array : used to indicate a res_id in case of a many2one field
res_id = array[0]
field_diplay_value = array[1]
Since we cannot use the array format to send the date(time)s of the period range
because it could be confused with the many2one format, this commit introduces
the use of a new `__range` key which is a dictionary with specific related
keys to be used to defer usable data to the web client.
Task-ID: 2243913
PR odoo/odoo#69380
64 lines
2.0 KiB
Python
64 lines
2.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo.tests import common
|
|
|
|
|
|
class TestEmptyDate(common.TransactionCase):
|
|
""" Test what happens when grouping on date fields and getting a "false"
|
|
grouping value
|
|
"""
|
|
def setUp(self):
|
|
super(TestEmptyDate, self).setUp()
|
|
self.Model = self.env['test_read_group.on_date']
|
|
|
|
def test_empty_only(self):
|
|
self.Model.create({'value': 1})
|
|
self.Model.create({'value': 2})
|
|
self.Model.create({'value': 3})
|
|
|
|
gb = self.Model.read_group([], ['date', 'value'], ['date'], lazy=False)
|
|
|
|
self.assertEqual(gb, [{
|
|
'__count': 3,
|
|
'__domain': [('date', '=', False)],
|
|
'__range': {'date': False},
|
|
'date': False,
|
|
'value': 6
|
|
}])
|
|
|
|
def test_empty_by_span(self):
|
|
self.Model.create({'value': 1})
|
|
self.Model.create({'value': 2})
|
|
self.Model.create({'value': 3})
|
|
|
|
gb = self.Model.read_group([], ['date', 'value'], ['date:quarter'], lazy=False)
|
|
|
|
self.assertEqual(gb, [{
|
|
'__count': 3,
|
|
'__domain': [('date', '=', False)],
|
|
'__range': {'date': False},
|
|
'date:quarter': False,
|
|
'value': 6
|
|
}])
|
|
|
|
def test_mixed(self):
|
|
self.Model.create({'date': False, 'value': 1})
|
|
self.Model.create({'date': False, 'value': 2})
|
|
self.Model.create({'date': '1916-12-18', 'value': 3})
|
|
self.Model.create({'date': '1916-12-18', 'value': 4})
|
|
|
|
gb = self.Model.read_group([], ['date', 'value'], ['date'], lazy=False)
|
|
|
|
self.assertSequenceEqual(sorted(gb, key=lambda r: r['date'] or ''), [{
|
|
'__count': 2,
|
|
'__domain': [('date', '=', False)],
|
|
'__range': {'date': False},
|
|
'date': False,
|
|
'value': 3,
|
|
}, {
|
|
'__count': 2,
|
|
'__domain': ['&', ('date', '>=', '1916-12-01'), ('date', '<', '1917-01-01')],
|
|
'__range': {'date': {'from': '1916-12-01', 'to': '1917-01-01'}},
|
|
'date': 'December 1916',
|
|
'value': 7,
|
|
}])
|