[ADD] web_time_range_menu_custom

This commit is contained in:
Alexandre D. Díaz
2021-09-20 13:04:50 +02:00
committed by Carlos Roca
parent 266ed71fd0
commit 9dc3acb296
16 changed files with 1234 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
odoo.define("web_time_range_menu_custom.ControlPanelController", function(require) {
"use strict";
const ControlPanelController = require("web.ControlPanelController");
ControlPanelController.include({
custom_events: _.extend({}, ControlPanelController.prototype.custom_events, {
activate_custom_time_range: "_onActivateCustomTimeRange",
}),
/**
* @override
*/
_onActivateCustomTimeRange: function(ev) {
ev.stopPropagation();
this.model.activateTimeRangeCustom(
ev.data.id,
ev.data.timeRangeId,
ev.data.comparisonTimeRangeId,
ev.data.timeRangeCustom,
ev.data.comparisonTimeRangeCustom
);
this._reportNewQueryAndRender();
},
});
});

View File

@@ -0,0 +1,83 @@
/* Copyright 2021 Tecnativa - Alexandre D. Díaz
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
odoo.define("web_time_range_menu_custom.ControlPanelModel", function(require) {
"use strict";
const core = require("web.core");
const Domain = require("web.Domain");
const ControlPanelModel = require("web.ControlPanelModel");
const _t = core._t;
ControlPanelModel.include({
activateTimeRangeCustom: function(
filterId,
timeRangeId,
comparisonTimeRangeId,
timeRangeCustom,
comparisonTimeRangeCustom
) {
var filter = this.filters[filterId];
filter.timeRangeCustom = timeRangeCustom;
filter.comparisonTimeRangeCustom = comparisonTimeRangeCustom;
this.activateTimeRange(filterId, timeRangeId, comparisonTimeRangeId);
},
/**
* @override
*/
_getTimeRangeMenuData: function(evaluation) {
const context = this._super.apply(this, arguments);
// GroupOfTimeRanges can be undefined in case with withSearchBar is false
var groupOfTimeRanges = this.groups[this._getGroupIdOfType("timeRange")];
if (groupOfTimeRanges && groupOfTimeRanges.activeFilterIds.length) {
var filter = this.filters[groupOfTimeRanges.activeFilterIds[0][0]];
if (filter.timeRangeId === "custom_period") {
context.timeRangeMenuData.timeRange = Domain.prototype.constructCustomDomain(
filter.fieldName,
filter.timeRangeId,
filter.fieldType,
undefined,
filter.timeRangeCustom
);
context.timeRangeMenuData.timeRangeDescription =
_t("Last ") +
`${filter.timeRangeCustom.value} ${filter.timeRangeCustom.type}`;
context.timeRangeMenuData.timeRangeCustomValue =
filter.timeRangeCustom.value;
context.timeRangeMenuData.timeRangeCustomType =
filter.timeRangeCustom.type;
if (evaluation) {
context.timeRangeMenuData.timeRange = Domain.prototype.stringToArray(
context.timeRangeMenuData.timeRange
);
}
}
if (filter.comparisonTimeRangeId === "custom_comparison_period") {
context.timeRangeMenuData.comparisonTimeRange = Domain.prototype.constructCustomDomain(
filter.fieldName,
filter.timeRangeId,
filter.fieldType,
filter.comparisonTimeRangeId,
filter.timeRangeCustom,
filter.comparisonTimeRangeCustom
);
context.timeRangeMenuData.comparisonTimeRangeDescription =
_t("Previous ") +
`${filter.comparisonTimeRangeCustom.value} ${filter.comparisonTimeRangeCustom.type}`;
context.timeRangeMenuData.comparisonTimeRangeCustomValue =
filter.comparisonTimeRangeCustom.value;
context.timeRangeMenuData.comparisonTimeRangeCustomType =
filter.comparisonTimeRangeCustom.type;
if (evaluation) {
context.timeRangeMenuData.comparisonTimeRange = Domain.prototype.stringToArray(
context.timeRangeMenuData.comparisonTimeRange
);
}
}
}
return context;
},
});
});

View File

@@ -0,0 +1,20 @@
/* Copyright 2021 Tecnativa - Alexandre D. Díaz
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
odoo.define("web_time_range_menu_custom.controlPanelViewParameters", function(require) {
"use strict";
const controlPanelViewParameters = require("web.controlPanelViewParameters");
const core = require("web.core");
const _lt = core._lt;
controlPanelViewParameters.PERIOD_OPTIONS = controlPanelViewParameters.PERIOD_OPTIONS.concat(
[{description: _lt("Custom Period"), optionId: "custom_period", groupId: 4}]
);
controlPanelViewParameters.TIME_RANGE_OPTIONS =
controlPanelViewParameters.PERIOD_OPTIONS;
controlPanelViewParameters.COMPARISON_TIME_RANGE_OPTIONS = controlPanelViewParameters.COMPARISON_TIME_RANGE_OPTIONS.concat(
[{description: _lt("Custom Period"), optionId: "custom_comparison_period"}]
);
});

View File

@@ -0,0 +1,240 @@
/* Copyright 2021 Tecnativa - Alexandre D. Díaz
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
odoo.define("web_time_range_menu_custom.Domain", function(require) {
"use strict";
const Domain = require("web.Domain");
Domain.include({
/**
* @override
*/
constructCustomDomain: function(
fieldName,
period,
type,
comparisonPeriod,
periodCustom,
comparisonPeriodCustom
) {
let leftBoundaryParams = {};
let rightBoundaryParams = {};
let offsetPeriodParams = 0;
// Cloned function from web.domain
// Necessary because inner function usage
// TODO: Check changes in new versions
function makeInterval() {
switch (comparisonPeriod) {
case "previous_period":
_.each(offsetPeriodParams, function(value, key) {
if (
!leftBoundaryParams[key] ||
_.isNumber(leftBoundaryParams[key])
) {
leftBoundaryParams[key] =
value + (leftBoundaryParams[key] || 0);
} else {
leftBoundaryParams[key] =
value + " + " + leftBoundaryParams[key];
}
if (
!rightBoundaryParams[key] ||
_.isNumber(rightBoundaryParams[key])
) {
rightBoundaryParams[key] =
value + (rightBoundaryParams[key] || 0);
} else {
rightBoundaryParams[key] =
value + " + " + rightBoundaryParams[key];
}
});
break;
case "previous_year":
leftBoundaryParams.years = leftBoundaryParams.years
? leftBoundaryParams.years - 1
: -1;
rightBoundaryParams.years = rightBoundaryParams.years
? rightBoundaryParams.years - 1
: -1;
break;
case "custom_comparison_period":
// This case is the addition for custom periods
leftBoundaryParams[
comparisonPeriodCustom.type
] = leftBoundaryParams[comparisonPeriodCustom.type]
? leftBoundaryParams[comparisonPeriodCustom.type] -
comparisonPeriodCustom.value
: -comparisonPeriodCustom.value;
rightBoundaryParams[
comparisonPeriodCustom.type
] = rightBoundaryParams[comparisonPeriodCustom.type]
? rightBoundaryParams[comparisonPeriodCustom.type] -
comparisonPeriodCustom.value
: -comparisonPeriodCustom.value;
break;
}
var stringifyParams = function(value, key) {
return key + "=" + value;
};
var leftBoundaryStringifyParams = _.map(
leftBoundaryParams,
stringifyParams
).join(", ");
var rightBoundaryStringifyParams = _.map(
rightBoundaryParams,
stringifyParams
).join(", ");
if (type === "date") {
return (
"['&'," +
"('" +
fieldName +
"', '>=', (context_today() + relativedelta(" +
leftBoundaryStringifyParams +
")).strftime('%Y-%m-%d'))," +
"('" +
fieldName +
"', '<', (context_today() + relativedelta(" +
rightBoundaryStringifyParams +
")).strftime('%Y-%m-%d'))" +
"]"
);
}
return (
"['&'," +
"('" +
fieldName +
"', '>=', " +
"(datetime.datetime.combine(context_today() + relativedelta(" +
leftBoundaryStringifyParams +
"), datetime.time(0,0,0)).to_utc()).strftime('%Y-%m-%d %H:%M:%S'))," +
"('" +
fieldName +
"', '<', " +
"(datetime.datetime.combine(context_today() + relativedelta(" +
rightBoundaryStringifyParams +
"), datetime.time(0,0,0)).to_utc()).strftime('%Y-%m-%d %H:%M:%S'))" +
"]"
);
}
function defineCustom() {
if (periodCustom.type === "years") {
leftBoundaryParams = {month: 1, day: 1, years: -periodCustom.value};
rightBoundaryParams = {month: 1, day: 1};
offsetPeriodParams = {years: -periodCustom.value};
} else if (periodCustom.type === "months") {
leftBoundaryParams = {day: 1, months: -periodCustom.value};
rightBoundaryParams = {day: 1};
offsetPeriodParams = {months: -periodCustom.value};
} else if (periodCustom.type === "weeks") {
leftBoundaryParams = {
days: 1,
weekday: 0,
weeks: -periodCustom.value,
};
rightBoundaryParams = {days: 1, weekday: 0};
offsetPeriodParams = {weeks: -periodCustom.value};
} else if (periodCustom.type === "days") {
leftBoundaryParams = {days: -periodCustom.value};
rightBoundaryParams = {};
offsetPeriodParams = {days: -periodCustom.value};
}
}
// Cloned from web.domain
// Necessary because can have customPeriod or/and comparisonPeriodCustom
// TODO: Check changes in new versions
switch (period) {
case "today":
leftBoundaryParams = {};
rightBoundaryParams = {days: 1};
offsetPeriodParams = {days: -1};
return makeInterval();
case "this_week":
leftBoundaryParams = {weeks: -1, days: 1, weekday: 0};
rightBoundaryParams = {days: 1, weekday: 0};
offsetPeriodParams = {weeks: -1};
return makeInterval();
case "this_month":
leftBoundaryParams = {day: 1};
rightBoundaryParams = {day: 1, months: 1};
offsetPeriodParams = {months: -1};
return makeInterval();
case "this_quarter":
leftBoundaryParams = {
months: "- (context_today().month - 1) % 3",
day: 1,
};
rightBoundaryParams = {
months: "3 - (context_today().month - 1) % 3",
day: 1,
};
offsetPeriodParams = {months: -3};
return makeInterval();
case "this_year":
leftBoundaryParams = {month: 1, day: 1};
rightBoundaryParams = {month: 1, day: 1, years: 1};
offsetPeriodParams = {years: -1};
return makeInterval();
case "yesterday":
leftBoundaryParams = {days: -1};
rightBoundaryParams = {};
offsetPeriodParams = {days: -1};
return makeInterval();
case "last_week":
leftBoundaryParams = {weeks: -2, days: 1, weekday: 0};
rightBoundaryParams = {weeks: -1, days: 1, weekday: 0};
offsetPeriodParams = {weeks: -1};
return makeInterval();
case "last_month":
leftBoundaryParams = {months: -1, day: 1};
rightBoundaryParams = {day: 1};
offsetPeriodParams = {months: -1};
return makeInterval();
case "last_quarter":
leftBoundaryParams = {
months: "- 3 - (context_today().month - 1) % 3",
day: 1,
};
rightBoundaryParams = {
months: "- (context_today().month - 1) % 3",
day: 1,
};
offsetPeriodParams = {months: -3};
return makeInterval();
case "last_year":
leftBoundaryParams = {month: 1, day: 1, years: -1};
rightBoundaryParams = {month: 1, day: 1};
offsetPeriodParams = {years: -1};
return makeInterval();
case "last_7_days":
leftBoundaryParams = {days: -7};
rightBoundaryParams = {};
offsetPeriodParams = {days: -7};
return makeInterval();
case "last_30_days":
leftBoundaryParams = {days: -30};
rightBoundaryParams = {};
offsetPeriodParams = {days: -30};
return makeInterval();
case "last_365_days":
leftBoundaryParams = {days: -365};
rightBoundaryParams = {};
offsetPeriodParams = {days: -365};
return makeInterval();
case "last_5_years":
leftBoundaryParams = {years: -5};
rightBoundaryParams = {};
offsetPeriodParams = {years: -5};
return makeInterval();
case "custom_period":
// This case is the addition for custom periods
defineCustom();
return makeInterval();
}
},
});
});

View File

@@ -0,0 +1,57 @@
/* Copyright 2021 Tecnativa - Alexandre D. Díaz
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
odoo.define("web_time_range_menu_custom.SearchFacet", function(require) {
"use strict";
const core = require("web.core");
const SearchFacet = require("web.SearchFacet");
const _t = core._t;
SearchFacet.include({
/**
* @override
*/
_getFilterDescription: function(filter) {
if (
filter.type === "timeRange" &&
(filter.timeRangeId === "custom_period" ||
filter.comparisonTimeRangeId === "custom_comparison_period")
) {
let description = filter.description;
if (filter.timeRangeId === "custom_period") {
description +=
": " +
_t("Last ") +
`${filter.timeRangeCustom.value} ${filter.timeRangeCustom.type}`;
} else {
var timeRangeValue = _.findWhere(filter.timeRangeOptions, {
optionId: filter.timeRangeId,
});
description += ": " + timeRangeValue.description;
}
if (filter.comparisonTimeRangeId) {
if (filter.comparisonTimeRangeId === "custom_comparison_period") {
description +=
" / " +
_t("Previous ") +
`${filter.comparisonTimeRangeCustom.value} ${filter.comparisonTimeRangeCustom.type}`;
} else {
var comparisonTimeRangeValue = _.findWhere(
filter.comparisonTimeRangeOptions,
{
optionId: filter.comparisonTimeRangeId,
}
);
description += " / " + comparisonTimeRangeValue.description;
}
}
return description;
}
return this._super.apply(this, arguments);
},
});
});

View File

@@ -0,0 +1,138 @@
/* Copyright 2021 Tecnativa - Alexandre D. Díaz
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
odoo.define("web_time_range_menu_custom.TimeRangeMenu", function(require) {
"use strict";
const TimeRangeMenu = require("web.TimeRangeMenu");
TimeRangeMenu.include({
events: _.extend({}, TimeRangeMenu.prototype.events, {
"change #time_range_selector": "_onChangeTimeRangeSelector",
"change .o_comparison_time_range_selector":
"_onChangeComparisonTimeRangeSelector",
}),
renderElement: function() {
this._super.apply(this, arguments);
this.$time_range_selector = this.$el.find("#time_range_selector");
this.$comparison_time_range_selector = this.$el.find(
".o_comparison_time_range_selector"
);
this.$selector_custom = this.$el.find("#time_range_selector_custom");
this.$selector_custom_field_value = this.$selector_custom.find(
"#date_field_selector_custom_value"
);
this.$selector_custom_field_type = this.$selector_custom.find(
"#date_field_selector_custom_type"
);
this.$selector_comparison_custom = this.$el.find(
"#comparison_time_range_selector_custom"
);
this.$selector_comparison_custom_field_value = this.$selector_comparison_custom.find(
"#date_field_selector_comparison_custom_value"
);
this.$selector_comparison_custom_field_type = this.$selector_comparison_custom.find(
"#date_field_selector_comparison_custom_type"
);
this.$selector_custom.toggleClass(
"d-none",
this.$time_range_selector.val() !== "custom_period"
);
this.$selector_comparison_custom.toggleClass(
"d-none",
this.$comparison_time_range_selector.val() !==
"custom_comparison_period"
);
if (!_.isEmpty(this.timeRangeCustom)) {
this.$selector_custom_field_value.val(this.timeRangeCustom.value);
this.$selector_custom_field_type.val(this.timeRangeCustom.type);
}
if (!_.isEmpty(this.comparisonTimeRangeCustom)) {
this.$selector_comparison_custom_field_value.val(
this.comparisonTimeRangeCustom.value
);
this.$selector_comparison_custom_field_type.val(
this.comparisonTimeRangeCustom.type
);
}
},
_onChangeTimeRangeSelector: function(ev) {
this.$selector_custom.toggleClass(
"d-none",
ev.target.value !== "custom_period"
);
},
_onChangeComparisonTimeRangeSelector: function(ev) {
this.$selector_comparison_custom.toggleClass(
"d-none",
ev.target.value !== "custom_comparison_period"
);
},
_onCheckBoxClick: function() {
this._super.apply(this, arguments);
const comparisonTimeRangeId = this.$(
".o_comparison_time_range_selector"
).val();
this.$selector_comparison_custom.toggleClass(
"d-none",
!this.configuration.comparisonIsSelected ||
comparisonTimeRangeId !== "custom_comparison_period"
);
},
_onApplyButtonClick: function() {
const id = this.$(".o_date_field_selector").val();
const timeRangeId = this.$(".o_time_range_selector").val();
let comparisonTimeRangeId = false;
if (this.configuration.comparisonIsSelected) {
comparisonTimeRangeId = this.$(
".o_comparison_time_range_selector"
).val();
}
if (
timeRangeId !== "custom_period" &&
comparisonTimeRangeId !== "custom_comparison_period"
) {
return this._super.apply(this, arguments);
}
const values = {
id: id,
timeRangeId: timeRangeId,
comparisonTimeRangeId: comparisonTimeRangeId,
};
this.timeRangeCustom = null;
if (timeRangeId === "custom_period") {
const value = this.$selector_custom_field_value.val();
const type = this.$selector_custom_field_type.val();
if (!value || !type) {
return false;
}
this.timeRangeCustom = {
value: value,
type: type,
};
values.timeRangeCustom = this.timeRangeCustom;
}
this.comparisonTimeRangeCustom = null;
if (comparisonTimeRangeId === "custom_comparison_period") {
const value = this.$selector_comparison_custom_field_value.val();
const type = this.$selector_comparison_custom_field_type.val();
if (!value || !type) {
return false;
}
this.comparisonTimeRangeCustom = {
value: value,
type: type,
};
values.comparisonTimeRangeCustom = this.comparisonTimeRangeCustom;
}
this.trigger_up("activate_custom_time_range", values);
},
});
});

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" ?>
<template>
<t t-name="web_time_range_menu_custom.CustomZone">
<div class="d-flex">
<input type="number" min="1" t-att-id="field_value" class="o_input" />
<select t-att-id="field_type" class="o_input o_date_field_selector">
<option value="days">Day</option>
<option value="weeks">Week</option>
<option value="months">Month</option>
<option value="years">Year</option>
</select>
</div>
</t>
<t t-extend="web.TimeRangeMenu">
<t
t-jquery="div.dropdown-item-text:has(#time_range_selector)"
t-operation="after"
>
<div class="dropdown-item-text d-none" id="time_range_selector_custom">
<t t-call="web_time_range_menu_custom.CustomZone">
<t
t-set="field_value"
t-value="'date_field_selector_custom_value'"
/>
<t t-set="field_type" t-value="'date_field_selector_custom_type'" />
</t>
</div>
</t>
<t
t-jquery="div.dropdown-item-text:has(.o_comparison_checkbox)"
t-operation="after"
>
<div
class="dropdown-item-text d-none"
id="comparison_time_range_selector_custom"
>
<t t-call="web_time_range_menu_custom.CustomZone">
<t
t-set="field_value"
t-value="'date_field_selector_comparison_custom_value'"
/>
<t
t-set="field_type"
t-value="'date_field_selector_comparison_custom_type'"
/>
</t>
</div>
</t>
</t>
</template>