[FIX] web: fix date filters

Issue

    If month - 1 or month - 2 are in the previous year, the filter is
    incorrect.

    ex: Date = Jan. 2020, Filter = Dec. 2019
        => last_year__last_month = 2018-12 instead 2019-12

Cause

    If date is 2020-01-20

    Selecting December => adding param "last_month"
    Selecting 2019 => adding param "last_year"

    Applying "last_month" => date become 2019-12-01
    Applying "last_year" => date become 2018-12-01

Solution

    Detect the right year to activate by default
    when a month is selected and no year is selected.
    With that solution it is not possible to get records in Jan. 2020
    or in Dec. 2019 only for instance but the global functioning
    of date filters stays the same as before.

OPW-2169528

closes odoo/odoo#44208

X-original-commit: 096fdc7d3fe0799aa761c6ad3597569a002c698e
Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
Co-authored-by: Jason Van Malder <jvm@odoo.com>
This commit is contained in:
Mathieu Duckerts-Antoine
2020-02-03 13:57:17 +00:00
co-authored by Jason Van Malder
parent 68f5883aff
commit 95f40530f3
3 changed files with 73 additions and 22 deletions
@@ -420,7 +420,7 @@ var ControlPanelModel = mvc.Model.extend({
}
if (filter.currentOptionIds) {
filter.currentOptionIds.clear();
}
}
})
group.activeFilterIds = [];
});
@@ -459,9 +459,13 @@ var ControlPanelModel = mvc.Model.extend({
acc.push(y.optionId);
}
return acc;
},
},
[]
);
const defaultYearId = (optionId) => {
const year = filter.options.find(o => o.optionId === optionId).defaultYear;
return filter.options.find(o => o.setParam.year === year).optionId;
};
if (filter.type === 'filter') {
const alreadyActive = group.activeFilterIds.some(isEqualTo([filterId]));
@@ -486,7 +490,7 @@ var ControlPanelModel = mvc.Model.extend({
filter.currentOptionIds.add(optionId);
if (!selectedYears().length) {
// Here we add 'this_year' as options if no option of type year is already selected.
filter.currentOptionIds.add('this_year');
filter.currentOptionIds.add(defaultYearId(optionId));
}
}
} else if (filter.type === 'groupBy') {
@@ -726,8 +730,8 @@ var ControlPanelModel = mvc.Model.extend({
return pyUtils.assembleDomains(domains, 'AND');
},
/**
* Return an array containing 'facets' used to create the content of the search bar.
*
* Return an array containing 'facets' used to create the content of the search bar.
*
* @returns {Object}
*/
_getFacets: function () {
@@ -13,7 +13,6 @@ var Domain = require('web.Domain');
var DEFAULT_INTERVAL = controlPanelViewParameters.DEFAULT_INTERVAL;
var DEFAULT_PERIOD = controlPanelViewParameters.DEFAULT_PERIOD;
var INTERVAL_OPTIONS = controlPanelViewParameters.INTERVAL_OPTIONS;
var PERIOD_OPTIONS = controlPanelViewParameters.PERIOD_OPTIONS;
const OPTION_GENERATORS = controlPanelViewParameters.OPTION_GENERATORS;
var Factory = mvc.Factory;
@@ -74,18 +73,28 @@ var ControlPanelView = Factory.extend({
this.fields = viewInfo.fields;
this.referenceMoment = moment();
this.optionGenerators = OPTION_GENERATORS.map(o => {
const description = o.description ?
const setDescriptions = (options) => {
return options.map(o => {
const oClone = JSON.parse(JSON.stringify(o));
const description = o.description ?
o.description.toString () :
this.referenceMoment.clone().set(o.setParam).add(o.addParam).format(o.format);
return _.extend({}, o, {description: description});
});
PERIOD_OPTIONS = PERIOD_OPTIONS.map(option =>
_.extend({}, option, {description: option.description.toString()})
);
INTERVAL_OPTIONS = INTERVAL_OPTIONS.map(option =>
_.extend({}, option, {description: option.description.toString()})
);
this.referenceMoment.clone().add(o.addParam).format(o.format);
return _.extend(oClone, {description: description});
});
};
const process = (options) => {
return options.map(o => {
const date = this.referenceMoment.clone().set(o.setParam).add(o.addParam);
delete o.addParam;
o.setParam[o.granularity] = date[o.granularity]();
o.defaultYear = date.year();
return o;
});
}
this.optionGenerators = process(setDescriptions(OPTION_GENERATORS));
this.intervalOptions = setDescriptions(INTERVAL_OPTIONS);
this.controllerParams.modelName = params.modelName;
@@ -196,7 +205,7 @@ var ControlPanelView = Factory.extend({
filter.fieldType = this.fields[attrs.fieldName].type;
if (_.contains(['date', 'datetime'], filter.fieldType)) {
filter.hasOptions = true;
filter.options = INTERVAL_OPTIONS;
filter.options = this.intervalOptions;
filter.defaultOptionId = attrs.defaultInterval ||
DEFAULT_INTERVAL;
filter.currentOptionIds = new Set();
@@ -227,10 +236,9 @@ var ControlPanelView = Factory.extend({
*/
_getDateFilterBasicDomains: function (filter) {
const _constructBasicDomain = (y, o) => {
const addParam = _.extend({}, y.addParam, o ? o.addParam : {});
const setParam = _.extend({}, y.setParam, o ? o.setParam : {});
const setParam = Object.assign({}, y.setParam, o ? o.setParam : {});
const granularity = o ? o.granularity : y.granularity;
const date = this.referenceMoment.clone().set(setParam).add(addParam);
const date = this.referenceMoment.clone().set(setParam);
let leftBound = date.clone().startOf(granularity).locale('en');
let rightBound = date.clone().endOf(granularity).locale('en');
@@ -753,7 +753,7 @@ QUnit.module('Search View', {
var self = this;
this.archs['partner,4,search'] = '<search>'+
'<filter string="AAA" name="some_filter" date="date_field" default_period="this_week"></filter>' +
'<filter string="AAA" name="some_filter" date="date_field"></filter>' +
'</search>';
var unpatchDate = patchDate(2017,2,22,1,0,0);
@@ -803,6 +803,45 @@ QUnit.module('Search View', {
unpatchDate();
});
QUnit.test('filter by a date field using period works even in January', async function (assert) {
assert.expect(3);
this.archs['partner,4,search'] = '<search>'+
'<filter string="AAA" name="some_filter" date="date_field" default_period="last_month"></filter>' +
'</search>';
var unpatchDate = patchDate(2017,0,7,3,0,0);
var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function(route, args) {
if (route === '/web/dataset/search_read' && args.domain.length) {
assert.deepEqual(args.domain,
['&', ["date_field", ">=", "2016-12-01"], ["date_field", "<=", "2016-12-31"]]
);
}
return this._super.apply(this, arguments);
},
});
this.actions[4].context = {search_default_some_filter: true};
await actionManager.doAction(5);
// open menu 'Filter'
await testUtils.dom.click($('.o_search_options .fa-filter'));
// open menu options
await testUtils.dom.click($('.o_menu_item'));
assert.hasClass($('.o_item_option[data-option_id="last_month"] a'), 'selected');
assert.hasClass($('.o_item_option[data-option_id="last_year"] a'), 'selected');
actionManager.destroy();
unpatchDate();
});
QUnit.test('`context` key in <filter> is used', async function (assert) {
assert.expect(3);