425 lines
16 KiB
Python
425 lines
16 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Test for date ranges."""
|
|
|
|
from odoo.tests import common
|
|
|
|
|
|
class TestDateRange(common.TransactionCase):
|
|
"""Test for date ranges.
|
|
|
|
When grouping on date/datetime fields, group.__range is populated with
|
|
formatted string dates which can be accurately converted to date objects
|
|
(backend and frontend), since the display value format can vary greatly and
|
|
it is not always possible to translate that display value to a real date.
|
|
"""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.Model = cls.env['test_read_group.on_date']
|
|
|
|
def test_undefined_range(self):
|
|
"""Test an undefined range.
|
|
|
|
Records with an unset date value should be grouped in a group whose
|
|
range is False.
|
|
"""
|
|
self.Model.create({'date': False, 'value': 1})
|
|
|
|
expected = [{
|
|
'__domain': [('date', '=', False)],
|
|
'__range': {'date': False},
|
|
'date': False,
|
|
'date_count': 1,
|
|
'value': 1
|
|
}]
|
|
|
|
groups = self.Model.read_group([], fields=['date', 'value'], groupby=['date'])
|
|
self.assertEqual(groups, expected)
|
|
|
|
def test_with_default_granularity(self):
|
|
"""Test a range with the default granularity.
|
|
|
|
The default granularity is 'month' and is implied when not specified.
|
|
The key in group.__range should match the key in group.
|
|
"""
|
|
self.Model.create({'date': '1916-02-11', 'value': 1})
|
|
|
|
expected = [{
|
|
'__domain': ['&', ('date', '>=', '1916-02-01'), ('date', '<', '1916-03-01')],
|
|
'__range': {'date': {'from': '1916-02-01', 'to': '1916-03-01'}},
|
|
'date': 'February 1916',
|
|
'date_count': 1,
|
|
'value': 1
|
|
}]
|
|
|
|
groups = self.Model.read_group([], fields=['date', 'value'], groupby=['date'])
|
|
self.assertEqual(groups, expected)
|
|
|
|
def test_lazy_with_multiple_granularities(self):
|
|
"""Test a range with multiple granularities in lazy mode
|
|
|
|
The only value stored in __range should be the granularity of the first
|
|
groupby.
|
|
"""
|
|
self.Model.create({'date': '1916-02-11', 'value': 1})
|
|
|
|
expected = [{
|
|
'__domain': ['&', ('date', '>=', '1916-01-01'), ('date', '<', '1916-04-01')],
|
|
'__context': {'group_by': ['date:day']},
|
|
'__range': {'date:quarter': {'from': '1916-01-01', 'to': '1916-04-01'}},
|
|
'date:quarter': 'Q1 1916',
|
|
'date_count': 1,
|
|
'value': 1
|
|
}]
|
|
|
|
groups = self.Model.read_group([], fields=['date', 'value'], groupby=['date:quarter', 'date:day'])
|
|
self.assertEqual(groups, expected)
|
|
|
|
expected = [{
|
|
'__domain': ['&', ('date', '>=', '1916-02-11'), ('date', '<', '1916-02-12')],
|
|
'__context': {'group_by': ['date:quarter']},
|
|
'__range': {'date:day': {'from': '1916-02-11', 'to': '1916-02-12'}},
|
|
'date:day': '11 Feb 1916',
|
|
'date_count': 1,
|
|
'value': 1
|
|
}]
|
|
|
|
groups = self.Model.read_group([], fields=['date', 'value'], groupby=['date:day', 'date:quarter'])
|
|
self.assertEqual(groups, expected)
|
|
|
|
def test_not_lazy_with_multiple_granularities(self):
|
|
"""Test a range with multiple granularities (not lazy)
|
|
|
|
There should be a range for each granularity.
|
|
"""
|
|
self.Model.create({'date': '1916-02-11', 'value': 1})
|
|
|
|
expected = [{
|
|
'__domain': ['&',
|
|
'&', ('date', '>=', '1916-01-01'), ('date', '<', '1916-04-01'),
|
|
'&', ('date', '>=', '1916-02-11'), ('date', '<', '1916-02-12')
|
|
],
|
|
'__range': {
|
|
'date:quarter': {'from': '1916-01-01', 'to': '1916-04-01'},
|
|
'date:day': {'from': '1916-02-11', 'to': '1916-02-12'}
|
|
},
|
|
'date:quarter': 'Q1 1916',
|
|
'date:day': '11 Feb 1916',
|
|
'__count': 1,
|
|
'value': 1
|
|
}]
|
|
|
|
groups = self.Model.read_group([], fields=['date', 'value'], groupby=['date:quarter', 'date:day'], lazy=False)
|
|
self.assertEqual(groups, expected)
|
|
|
|
def test_duplicate_month(self):
|
|
records = self.Model.create([
|
|
{'date': '2022-01-29', 'value': 1}])
|
|
expected = [{
|
|
'__domain': ['&', '&', ('id', 'in', records.ids), '&', ('date', '>=', '2022-01-01'), ('date', '<', '2022-02-01'), ('date', '=', 'January 2022')],
|
|
'__count': 1,
|
|
'__range': {'date:month': {'from': '2022-01-01', 'to': '2022-02-01'}},
|
|
'value': 1,
|
|
'date:month': 'January 2022'
|
|
}]
|
|
groups = self.Model.read_group(
|
|
[('id', 'in', records.ids)], fields=['date', 'value'], groupby=['date:month', 'date:month'], lazy=False)
|
|
self.assertEqual(groups, expected)
|
|
|
|
|
|
class TestRelativeDateGranularity(common.TransactionCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.Model = cls.env['test_read_group.fill_temporal']
|
|
cls.Model.create([{"value": "1", "date": "2021-02-09", "datetime": "2021-02-09 15:55:12"},
|
|
{"value": "20", "date": "2021-06-01", "datetime": "2021-06-01 16:55:14"},
|
|
{"value": "300", "date": "2022-02-01", "datetime": "2022-02-01 15:22:12"}])
|
|
|
|
def test_full_usecase_month(self):
|
|
result = self.Model.read_group([],
|
|
fields=['date', 'value'],
|
|
groupby=['date:month_number'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'date:month_number': 2,
|
|
'date_count': 2,
|
|
'value': 301,
|
|
'__domain': [('date.month_number', '=', 2)]
|
|
}, {
|
|
'date:month_number': 6,
|
|
'date_count': 1,
|
|
'value': 20,
|
|
'__domain': [('date.month_number', '=', 6)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 2)
|
|
self.assertEqual(res.mapped('value'), [1, 300])
|
|
|
|
def test_full_usecase_iso_week(self):
|
|
result = self.Model.read_group([],
|
|
fields=['date', 'value'],
|
|
groupby=['date:iso_week_number'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'date:iso_week_number': 5,
|
|
'date_count': 1,
|
|
'value': 300,
|
|
'__domain': [('date.iso_week_number', '=', 5)]
|
|
}, {
|
|
'date:iso_week_number': 6,
|
|
'date_count': 1,
|
|
'value': 1,
|
|
'__domain': [('date.iso_week_number', '=', 6)]
|
|
}, {
|
|
'date:iso_week_number': 22,
|
|
'date_count': 1,
|
|
'value': 20,
|
|
'__domain': [('date.iso_week_number', '=', 22)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 1)
|
|
self.assertEqual(res.mapped('value'), [300])
|
|
|
|
def test_full_usecase_quarter(self):
|
|
result = self.Model.read_group([],
|
|
fields=['date', 'value'],
|
|
groupby=['date:quarter_number'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'date:quarter_number': 1,
|
|
'date_count': 2,
|
|
'value': 301,
|
|
'__domain': [('date.quarter_number', '=', 1)]
|
|
}, {
|
|
'date:quarter_number': 2,
|
|
'date_count': 1,
|
|
'value': 20,
|
|
'__domain': [('date.quarter_number', '=', 2)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 2)
|
|
self.assertEqual(res.mapped('value'), [1, 300])
|
|
|
|
def test_full_usecase_year(self):
|
|
result = self.Model.read_group([],
|
|
fields=['date', 'value'],
|
|
groupby=['date:year_number'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'date:year_number': 2021,
|
|
'date_count': 2,
|
|
'value': 21,
|
|
'__domain': [('date.year_number', '=', 2021)]
|
|
}, {
|
|
'date:year_number': 2022,
|
|
'date_count': 1,
|
|
'value': 300,
|
|
'__domain': [('date.year_number', '=', 2022)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 2)
|
|
self.assertEqual(res.mapped('value'), [1, 20])
|
|
|
|
def test_full_usecase_day_of_year(self):
|
|
result = self.Model.read_group([],
|
|
fields=['date', 'value'],
|
|
groupby=['date:day_of_year'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'date:day_of_year': 32,
|
|
'date_count': 1,
|
|
'value': 300,
|
|
'__domain': [('date.day_of_year', '=', 32)]
|
|
}, {
|
|
'date:day_of_year': 40,
|
|
'date_count': 1,
|
|
'value': 1,
|
|
'__domain': [('date.day_of_year', '=', 40)]
|
|
}, {
|
|
'date:day_of_year': 152,
|
|
'date_count': 1,
|
|
'value': 20,
|
|
'__domain': [('date.day_of_year', '=', 152)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 1)
|
|
self.assertEqual(res.mapped('value'), [300])
|
|
|
|
def test_full_usecase_day_of_month(self):
|
|
result = self.Model.read_group([],
|
|
fields=['date', 'value'],
|
|
groupby=['date:day_of_month'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'date:day_of_month': 1,
|
|
'date_count': 2,
|
|
'value': 320,
|
|
'__domain': [('date.day_of_month', '=', 1)]
|
|
}, {
|
|
'date:day_of_month': 9,
|
|
'date_count': 1,
|
|
'value': 1,
|
|
'__domain': [('date.day_of_month', '=', 9)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 2)
|
|
self.assertEqual(res.mapped('value'), [20, 300])
|
|
|
|
def test_full_usecase_day_of_week(self):
|
|
result = self.Model.read_group([],
|
|
fields=['date', 'value'],
|
|
groupby=['date:day_of_week'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'date:day_of_week': 2,
|
|
'date_count': 3,
|
|
'value': 321,
|
|
'__domain': [('date.day_of_week', '=', 2)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 3)
|
|
self.assertEqual(res.mapped('value'), [1, 20, 300])
|
|
|
|
def test_full_usecase_hour_number(self):
|
|
result = self.Model.read_group([],
|
|
fields=['datetime', 'value'],
|
|
groupby=['datetime:hour_number'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'datetime:hour_number': 15,
|
|
'datetime_count': 2,
|
|
'value': 301,
|
|
'__domain': [('datetime.hour_number', '=', 15)]
|
|
}, {
|
|
'datetime:hour_number': 16,
|
|
'datetime_count': 1,
|
|
'value': 20,
|
|
'__domain': [('datetime.hour_number', '=', 16)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 2)
|
|
self.assertEqual(res.mapped('value'), [1, 300])
|
|
|
|
def test_full_usecase_minute_number(self):
|
|
result = self.Model.read_group([],
|
|
fields=['datetime', 'value'],
|
|
groupby=['datetime:minute_number'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'datetime:minute_number': 22,
|
|
'datetime_count': 1,
|
|
'value': 300,
|
|
'__domain': [('datetime.minute_number', '=', 22)]
|
|
}, {
|
|
'datetime:minute_number': 55,
|
|
'datetime_count': 2,
|
|
'value': 21,
|
|
'__domain': [('datetime.minute_number', '=', 55)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 1)
|
|
self.assertEqual(res.mapped('value'), [300])
|
|
|
|
def test_full_usecase_second_number(self):
|
|
result = self.Model.read_group([],
|
|
fields=['datetime', 'value'],
|
|
groupby=['datetime:second_number'])
|
|
self.assertEqual(result, [
|
|
{
|
|
'datetime:second_number': 12,
|
|
'datetime_count': 2,
|
|
'value': 301,
|
|
'__domain': [('datetime.second_number', '=', 12)]
|
|
}, {
|
|
'datetime:second_number': 14,
|
|
'datetime_count': 1,
|
|
'value': 20,
|
|
'__domain': [('datetime.second_number', '=', 14)]
|
|
},
|
|
])
|
|
res = self.Model.search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 2)
|
|
self.assertEqual(res.mapped('value'), [1, 300])
|
|
|
|
def test_unknown_granularity(self):
|
|
with self.assertRaises(ValueError):
|
|
self.Model.read_group([], fields=['date', 'value'], groupby=['date:unknown_number'])
|
|
|
|
|
|
class TestRelativeDateGranularityWithTimezones(common.TransactionCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
# execute a read_group with a relative granularity, it will give us back a domain
|
|
# that contains the relative granularity to find the origin records. Use this domain
|
|
# to find those records. This is exactly the way the pivot view behaves.
|
|
super().setUpClass()
|
|
cls.Model = cls.env['test_read_group.fill_temporal']
|
|
cls.env['res.lang']._activate_lang('fr_BE')
|
|
cls.env['res.lang']._activate_lang('NZ')
|
|
|
|
def test_usecase_with_timezones(self):
|
|
# Monday, it is the 5th week in UTC and the 6th in NZ
|
|
self.Model.create({"value": "98", "datetime": "2023-02-05 23:55:00"})
|
|
result = (self.Model.with_context({'tz': 'Pacific/Auckland'}) # GMT+12
|
|
.read_group([],
|
|
fields=['datetime', 'value'],
|
|
groupby=['datetime:iso_week_number']))
|
|
self.assertEqual(result, [
|
|
{
|
|
'datetime:iso_week_number': 6,
|
|
'datetime_count': 1,
|
|
'value': 98,
|
|
'__domain': [('datetime.iso_week_number', '=', 6)]
|
|
}])
|
|
result = self.Model.with_context({'tz': 'Pacific/Auckland'}).search(result[0]['__domain'])
|
|
self.assertEqual(len(result), 1)
|
|
self.assertEqual(result.value, 98)
|
|
|
|
def test_day_of_week_with_monday_as_first_day_of_week(self):
|
|
self.Model.create({"value": "98", "date": "2023-02-05"}) # Sunday
|
|
|
|
result = (self.Model.with_context({'tz': 'fr_BE'}) # GMT+1, first day of week is Monday
|
|
.read_group([],
|
|
fields=['date', 'value'],
|
|
groupby=['date:day_of_week']))
|
|
self.assertEqual(result, [
|
|
{
|
|
'date:day_of_week': 6,
|
|
'date_count': 1,
|
|
'value': 98,
|
|
'__domain': [('date.day_of_week', '=', 6)]
|
|
}])
|
|
res = self.Model.with_context({'tz': 'fr_BE'}).search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 1)
|
|
self.assertEqual(res.mapped('value'), [98])
|
|
|
|
def test_day_of_week_with_sunday_as_first_day_of_week(self):
|
|
self.Model.create({"value": "98", "date": "2023-02-05"}) # Sunday
|
|
|
|
result = (self.Model.with_context({'tz': 'NZ'}) # GMT+12, first day of week is Sunday
|
|
.read_group([],
|
|
fields=['date', 'value'],
|
|
groupby=['date:day_of_week']))
|
|
self.assertEqual(result, [
|
|
{
|
|
'date:day_of_week': 0,
|
|
'date_count': 1,
|
|
'value': 98,
|
|
'__domain': [('date.day_of_week', '=', 0)]
|
|
}])
|
|
|
|
res = self.Model.with_context({'tz': 'NZ'}).search(result[0]['__domain'])
|
|
self.assertEqual(len(res), 1)
|
|
self.assertEqual(res.mapped('value'), [98])
|