diff --git a/web_time_range_menu_custom/README.rst b/web_time_range_menu_custom/README.rst index 6be1656f0..2a257df88 100644 --- a/web_time_range_menu_custom/README.rst +++ b/web_time_range_menu_custom/README.rst @@ -14,18 +14,19 @@ Web Time Range Menu Custom :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github - :target: https://github.com/OCA/web/tree/13.0/web_time_range_menu_custom + :target: https://github.com/OCA/web/tree/15.0/web_time_range_menu_custom :alt: OCA/web .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_time_range_menu_custom + :target: https://translation.odoo-community.org/projects/web-15-0/web-15-0-web_time_range_menu_custom :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/162/13.0 + :target: https://runbot.odoo-community.org/runbot/162/15.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| -Extend period and comparison period options for the time range menu adding a new option called "Custom Period". +Extend period and comparison period options for the date and datetime fields filted menu +adding a new option called "Custom Period". **Table of contents** @@ -38,7 +39,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -56,6 +57,7 @@ Contributors * `Tecnativa `__: * Alexandre D. Díaz + * Carlos Roca Maintainers ~~~~~~~~~~~ @@ -70,6 +72,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/web `_ project on GitHub. +This module is part of the `OCA/web `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_time_range_menu_custom/__manifest__.py b/web_time_range_menu_custom/__manifest__.py index 9cff15a64..54575213a 100644 --- a/web_time_range_menu_custom/__manifest__.py +++ b/web_time_range_menu_custom/__manifest__.py @@ -2,13 +2,20 @@ { "name": "Web Time Range Menu Custom", - "version": "13.0.1.0.1", + "version": "15.0.1.0.0", "author": "Tecnativa, Odoo Community Association (OCA)", "license": "AGPL-3", "website": "https://github.com/OCA/web", - "data": ["templates/assets.xml"], "depends": ["web"], - "qweb": ["static/src/xml/time_range_menu.xml"], "installable": True, "auto_install": False, + "assets": { + "web.assets_backend": [ + "/web_time_range_menu_custom/static/src/js/*.esm.js", + "/web_time_range_menu_custom/static/src/scss/*.scss", + ], + "web.assets_qweb": [ + "/web_time_range_menu_custom/static/src/xml/*.xml", + ], + }, } diff --git a/web_time_range_menu_custom/i18n/web_time_range_menu_custom.pot b/web_time_range_menu_custom/i18n/web_time_range_menu_custom.pot index c7b4ff32d..226eb6f7f 100644 --- a/web_time_range_menu_custom/i18n/web_time_range_menu_custom.pot +++ b/web_time_range_menu_custom/i18n/web_time_range_menu_custom.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 13.0\n" +"Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -15,52 +15,42 @@ msgstr "" #. module: web_time_range_menu_custom #. openerp-web -#: code:addons/web_time_range_menu_custom/static/src/js/control_panel_view_parameters.js:0 -#: code:addons/web_time_range_menu_custom/static/src/js/control_panel_view_parameters.js:0 +#: code:addons/web_time_range_menu_custom/static/src/xml/date_selector.xml:0 #, python-format -msgid "Custom Period" +msgid "Add" msgstr "" #. module: web_time_range_menu_custom #. openerp-web -#: code:addons/web_time_range_menu_custom/static/src/xml/time_range_menu.xml:0 +#: code:addons/web_time_range_menu_custom/static/src/xml/date_selector.xml:0 +#, python-format +msgid "Custom period" +msgstr "" + +#. module: web_time_range_menu_custom +#. openerp-web +#: code:addons/web_time_range_menu_custom/static/src/xml/date_selector.xml:0 #, python-format msgid "Day" msgstr "" #. module: web_time_range_menu_custom #. openerp-web -#: code:addons/web_time_range_menu_custom/static/src/js/control_panel_model.js:0 -#: code:addons/web_time_range_menu_custom/static/src/js/search_facet.js:0 -#, python-format -msgid "Last " -msgstr "" - -#. module: web_time_range_menu_custom -#. openerp-web -#: code:addons/web_time_range_menu_custom/static/src/xml/time_range_menu.xml:0 +#: code:addons/web_time_range_menu_custom/static/src/xml/date_selector.xml:0 #, python-format msgid "Month" msgstr "" #. module: web_time_range_menu_custom #. openerp-web -#: code:addons/web_time_range_menu_custom/static/src/js/control_panel_model.js:0 -#: code:addons/web_time_range_menu_custom/static/src/js/search_facet.js:0 -#, python-format -msgid "Previous " -msgstr "" - -#. module: web_time_range_menu_custom -#. openerp-web -#: code:addons/web_time_range_menu_custom/static/src/xml/time_range_menu.xml:0 +#: code:addons/web_time_range_menu_custom/static/src/xml/date_selector.xml:0 #, python-format msgid "Week" msgstr "" #. module: web_time_range_menu_custom #. openerp-web -#: code:addons/web_time_range_menu_custom/static/src/xml/time_range_menu.xml:0 +#: code:addons/web_time_range_menu_custom/static/src/xml/date_selector.xml:0 #, python-format msgid "Year" msgstr "" diff --git a/web_time_range_menu_custom/readme/CONTRIBUTORS.rst b/web_time_range_menu_custom/readme/CONTRIBUTORS.rst index 4d7b0e818..0b0b82ce1 100644 --- a/web_time_range_menu_custom/readme/CONTRIBUTORS.rst +++ b/web_time_range_menu_custom/readme/CONTRIBUTORS.rst @@ -1,3 +1,4 @@ * `Tecnativa `__: * Alexandre D. Díaz + * Carlos Roca diff --git a/web_time_range_menu_custom/readme/DESCRIPTION.rst b/web_time_range_menu_custom/readme/DESCRIPTION.rst index cf7193a63..6dca00fe8 100644 --- a/web_time_range_menu_custom/readme/DESCRIPTION.rst +++ b/web_time_range_menu_custom/readme/DESCRIPTION.rst @@ -1 +1,2 @@ -Extend period and comparison period options for the time range menu adding a new option called "Custom Period". +Extend period and comparison period options for the date and datetime fields filted menu +adding a new option called "Custom Period". diff --git a/web_time_range_menu_custom/static/description/index.html b/web_time_range_menu_custom/static/description/index.html index d73516242..939f99ef6 100644 --- a/web_time_range_menu_custom/static/description/index.html +++ b/web_time_range_menu_custom/static/description/index.html @@ -367,8 +367,9 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runbot

-

Extend period and comparison period options for the time range menu adding a new option called “Custom Period”.

+

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runbot

+

Extend period and comparison period options for the date and datetime fields filted menu +adding a new option called “Custom Period”.

Table of contents

    @@ -386,7 +387,7 @@ ul.auto-toc {

    Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

    +feedback.

    Do not contact contributors directly about support or help with technical issues.

@@ -402,6 +403,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome @@ -413,7 +415,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/web project on GitHub.

+

This module is part of the OCA/web project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/web_time_range_menu_custom/static/src/js/control_panel_controller.js b/web_time_range_menu_custom/static/src/js/control_panel_controller.js deleted file mode 100644 index 0ee8c98a7..000000000 --- a/web_time_range_menu_custom/static/src/js/control_panel_controller.js +++ /dev/null @@ -1,26 +0,0 @@ -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(); - }, - }); -}); diff --git a/web_time_range_menu_custom/static/src/js/control_panel_model.js b/web_time_range_menu_custom/static/src/js/control_panel_model.js deleted file mode 100644 index 0bb555ace..000000000 --- a/web_time_range_menu_custom/static/src/js/control_panel_model.js +++ /dev/null @@ -1,104 +0,0 @@ -/* 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 - ); - if (evaluation) { - context.timeRangeMenuData.comparisonTimeRange = - Domain.prototype.stringToArray( - context.timeRangeMenuData.comparisonTimeRange - ); - } - } - } - 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; - }, - }); -}); diff --git a/web_time_range_menu_custom/static/src/js/control_panel_view_parameters.js b/web_time_range_menu_custom/static/src/js/control_panel_view_parameters.js deleted file mode 100644 index f077c18c5..000000000 --- a/web_time_range_menu_custom/static/src/js/control_panel_view_parameters.js +++ /dev/null @@ -1,32 +0,0 @@ -/* 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", - }, - ]); - } -); diff --git a/web_time_range_menu_custom/static/src/js/date_selector.esm.js b/web_time_range_menu_custom/static/src/js/date_selector.esm.js new file mode 100644 index 000000000..71dcb3003 --- /dev/null +++ b/web_time_range_menu_custom/static/src/js/date_selector.esm.js @@ -0,0 +1,123 @@ +/** @odoo-module **/ +/* Copyright 2022 Tecnativa - Carlos Roca + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */ +import {useBus} from "@web/core/utils/hooks"; + +const {Component, QWeb} = owl; +const {useState} = owl.hooks; +import * as dates from "@web/search/utils/dates"; +const {DateTime} = luxon; // eslint-disable-line no-undef +var ID_CUSTOM_DATE = 0; + +/** + * @extends Component + */ +export class DropdownItemCustomPeriod extends Component { + setup() { + this.isOpen = useState({value: false}); + this.type = useState({value: "day"}); + this.quantity = useState({value: 0}); + this.referenceMoment = DateTime.local(); + var fieldsSelected = new Set(); + for (var selected in this.props.comparisonItems) { + fieldsSelected.add(this.props.comparisonItems[selected].dateFilterId); + } + this.fields_selected = Array.from(fieldsSelected); + this.field = useState({ + value: (this.props.field && this.props.field.id) || this.fields_selected[0], + }); + + useBus(this.env.searchModel, "update", this.render); + } + + onClickCustomPeriod() { + this.isOpen.value = !this.isOpen.value; + } + + onClickAdd() { + if (this.props.type === "filter") { + this.addRange(); + } else if (this.props.type === "comparison") { + this.addComparison(); + } + } + + addRange() { + const field_id = this.field.value; + const key = "custom_" + ID_CUSTOM_DATE++; + const plusParamID = this.type.value + "s"; + var formatSearch = ""; + switch (this.type.value) { + case "day": + formatSearch = "dd MMMM yyyy"; + break; + case "week": + formatSearch = "'W'WW yyyy"; + break; + case "month": + formatSearch = "MMMM"; + break; + case "year": + formatSearch = "yyyy"; + break; + } + const periodSearch = { + [key]: { + id: key, + groupNumber: 3, + description: + "Last " + this.quantity.value + " " + this.type.value + "s", + format: formatSearch, + plusParam: {[plusParamID]: -this.quantity.value}, + granularity: this.type.value, + custom_period: { + is_custom_period: true, + last_period: this.quantity.value, + }, + }, + }; + Object.assign(dates.PERIOD_OPTIONS, periodSearch); + this.env.searchModel.optionGenerators = dates.getPeriodOptions( + this.referenceMoment + ); + this.env.searchModel.toggleDateFilter(field_id, key); + } + + addComparison() { + const key = "custom_" + ID_CUSTOM_DATE++; + const plusParamID = this.type.value + "s"; + Object.assign(dates.COMPARISON_OPTIONS, { + [key]: { + description: + "Previous " + this.quantity.value + " " + this.type.value + "s", + id: key, + plusParam: {[plusParamID]: -this.quantity.value}, + }, + }); + const comparisonId = this.env.searchModel.nextId; + this.env.searchModel.searchItems[comparisonId] = { + comparisonOptionId: key, + dateFilterId: this.field.value, + description: + this.env.searchModel.searchItems[this.field.value].description + + ": Previous " + + this.quantity.value + + " " + + this.type.value + + "s", + groupId: 14, + id: comparisonId, + type: "comparison", + }; + this.env.searchModel.nextId++; + this.env.searchModel.toggleSearchItem(comparisonId); + } +} +DropdownItemCustomPeriod.template = + "web_time_range_menu_custom.DropdownItemCustomPeriod"; +DropdownItemCustomPeriod.props = { + type: {type: String}, + field: {type: Object, optional: true}, + comparisonItems: {type: Object, optional: true}, +}; +QWeb.registerComponent("DropdownItemCustomPeriod", DropdownItemCustomPeriod); diff --git a/web_time_range_menu_custom/static/src/js/dates.esm.js b/web_time_range_menu_custom/static/src/js/dates.esm.js new file mode 100644 index 000000000..9f619fa86 --- /dev/null +++ b/web_time_range_menu_custom/static/src/js/dates.esm.js @@ -0,0 +1,347 @@ +/** @odoo-module **/ +/* eslint-disable init-declarations */ +/* Copyright 2022 Tecnativa - Carlos Roca + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */ + +import {patch} from "@web/core/utils/patch"; +import {Domain} from "@web/core/domain"; +import {serializeDate, serializeDateTime} from "@web/core/l10n/dates"; +import {localization} from "@web/core/l10n/localization"; +/* Redefine some methods of dates.js from web.static.src.utils to +add support to days and weeks periods */ +import * as dates from "@web/search/utils/dates"; + +/** + * Method used to calculate the quantity of days and weeks of the + * actual year. + */ +function _getQtyOfCurrentYear(option) { + const now = new Date(); + const startOfYear = new Date(now.getFullYear(), 0, 1); + const endOfYear = new Date(now.getFullYear(), 11, 31); + let millisecondsPerWeek = 0; + if (option === "week") { + millisecondsPerWeek = 604800000; + } else if (option === "day") { + millisecondsPerWeek = 86400000; + } else { + return; + } + const weeks = Math.ceil((endOfYear - startOfYear) / millisecondsPerWeek); + return weeks; +} + +Object.assign(dates.PER_YEAR, { + week: _getQtyOfCurrentYear("week"), + day: _getQtyOfCurrentYear("day"), +}); + +// This is needed to call the super functions on @web/search/utils/dates +const _getSetParam = dates.getSetParam; + +// Patch of functions defined before +patch(dates, "patch dates", { + /* + * Redefine function to avoid the exclusion of days and weeks. + */ + constructDateDomain( + referenceMoment, + fieldName, + fieldType, + selectedOptionIds, + comparisonOptionId + ) { + let plusParam; + let selectedOptions; + if (comparisonOptionId) { + [plusParam, selectedOptions] = dates.getComparisonParams( + referenceMoment, + selectedOptionIds, + comparisonOptionId + ); + } else { + selectedOptions = dates.getSelectedOptions( + referenceMoment, + selectedOptionIds + ); + } + const yearOptions = selectedOptions.year; + const otherOptions = [ + ...(selectedOptions.quarter || []), + ...(selectedOptions.month || []), + ...(selectedOptions.day || []), + ...(selectedOptions.week || []), + ]; + dates.sortPeriodOptions(yearOptions); + dates.sortPeriodOptions(otherOptions); + const ranges = []; + for (const yearOption of yearOptions) { + const constructRangeParams = { + referenceMoment, + fieldName, + fieldType, + plusParam, + }; + if (otherOptions.length) { + for (const option of otherOptions) { + const setParam = Object.assign( + {}, + yearOption.setParam, + option ? option.setParam : {} + ); + const {granularity, custom_period} = option; + if (comparisonOptionId && custom_period.is_custom_period) { + custom_period.is_comparison = true; + } + const range = dates.constructDateRange( + Object.assign( + {granularity, custom_period, setParam}, + constructRangeParams + ) + ); + ranges.push(range); + } + } else { + const {granularity, custom_period, setParam} = yearOption; + if (comparisonOptionId && custom_period.is_custom_period) { + custom_period.is_comparison = true; + } + const range = dates.constructDateRange( + Object.assign( + {granularity, custom_period, setParam}, + constructRangeParams + ) + ); + ranges.push(range); + } + } + const domain = Domain.combine( + ranges.map((range) => range.domain), + "OR" + ); + const description = ranges.map((range) => range.description).join("/"); + return {domain, description}; + }, + constructDateRange(params) { + const { + referenceMoment, + fieldName, + fieldType, + granularity, + setParam, + plusParam, + custom_period, + } = params; + if ("quarter" in setParam) { + // Luxon does not consider quarter key in setParam (like moment did) + setParam.month = dates.QUARTERS[setParam.quarter].coveredMonths[0]; + delete setParam.quarter; + } + const plusParamReferenceMoment = referenceMoment.plus(plusParam || {}); + const date = referenceMoment.set(setParam).plus(plusParam || {}); + // Compute domain + const leftDate = date.startOf(granularity); + var rightDate = date.endOf(granularity); + if (custom_period.is_custom_period) { + rightDate = plusParamReferenceMoment; + } + let leftBound; + let rightBound; + if (fieldType === "date") { + leftBound = serializeDate(leftDate); + rightBound = serializeDate(rightDate); + } else { + leftBound = serializeDateTime(leftDate); + rightBound = serializeDateTime(rightDate); + } + const domain = new Domain([ + "&", + [fieldName, ">=", leftBound], + [fieldName, "<=", rightBound], + ]); + // Compute description + var description = ""; + if (custom_period.is_custom_period) { + if (plusParam) { + const key = Object.keys(plusParam)[0]; + description = "Previous " + Math.abs(plusParam[key]) + " " + key; + } else { + description = + "Last " + custom_period.last_period + " " + granularity + "s"; + } + } else { + var descriptions = [date.toFormat("yyyy")]; + const method = localization.direction === "rtl" ? "push" : "unshift"; + if (granularity === "month") { + descriptions[method](date.toFormat("MMMM")); + } else if (granularity === "quarter") { + const quarter = date.quarter; + descriptions[method](dates.QUARTERS[quarter].description.toString()); + } else if (granularity === "day") { + descriptions[method](date.toFormat("dd MMMM")); + } else if (granularity === "week") { + descriptions[method](date.toFormat("'W'WW")); + } + description = descriptions.join(" "); + } + return {domain, description}; + }, + /* + * Redefine function to allow process days and weeks. + */ + getPeriodOptions(referenceMoment) { + const options = []; + const originalOptions = Object.values(dates.PERIOD_OPTIONS); + for (const option of originalOptions) { + const {id, groupNumber} = option; + let description; + let defaultYear; + switch (option.granularity) { + case "quarter": + description = option.description.toString(); + defaultYear = referenceMoment.set(option.setParam).year; + break; + case "day": + case "week": + case "month": + case "year": + const date = referenceMoment.plus(option.plusParam); + description = option.description || date.toFormat(option.format); + defaultYear = date.year; + break; + } + const setParam = dates.getSetParam(option, referenceMoment); + options.push({id, groupNumber, description, defaultYear, setParam}); + } + const periodOptions = []; + for (const option of options) { + const {id, groupNumber, description, defaultYear} = option; + const yearOption = options.find( + (o) => o.setParam && o.setParam.year === defaultYear + ); + periodOptions.push({ + id, + groupNumber, + description, + defaultYearId: yearOption.id, + }); + } + return periodOptions; + }, + /* + * Add selection of month when week or day selected. + * + * @override + */ + getSetParam(periodOption, referenceMoment) { + if (periodOption.granularity === "day") { + const date = referenceMoment.plus(periodOption.plusParam); + return { + day: date.day, + month: date.month, + }; + } else if (periodOption.granularity === "week") { + const date = referenceMoment.plus(periodOption.plusParam); + return { + weekNumber: date.weekNumber, + }; + } + return _getSetParam(...arguments); + }, + getSelectedOptions(referenceMoment, selectedOptionIds) { + const selectedOptions = {year: []}; + for (const optionId of selectedOptionIds) { + const option = dates.PERIOD_OPTIONS[optionId]; + const setParam = dates.getSetParam(option, referenceMoment); + const custom_period = option.custom_period || {}; + const granularity = option.granularity; + if (!selectedOptions[granularity]) { + selectedOptions[granularity] = []; + } + selectedOptions[granularity].push({granularity, setParam, custom_period}); + } + return selectedOptions; + }, + /* + * Add support to day and week options. + * + */ + getComparisonParams(referenceMoment, selectedOptionIds, comparisonOptionId) { + const comparisonOption = dates.COMPARISON_OPTIONS[comparisonOptionId]; + const selectedOptions = dates.getSelectedOptions( + referenceMoment, + selectedOptionIds + ); + if (comparisonOption.plusParam) { + return [comparisonOption.plusParam, selectedOptions]; + } + const plusParam = {}; + let globalGranularity = "year"; + if (selectedOptions.day) { + globalGranularity = "day"; + } else if (selectedOptions.week) { + globalGranularity = "week"; + } else if (selectedOptions.month) { + globalGranularity = "month"; + } else if (selectedOptions.quarter) { + globalGranularity = "quarter"; + } + const granularityFactor = dates.PER_YEAR[globalGranularity]; + const years = selectedOptions.year.map((o) => o.setParam.year); + const yearMin = Math.min(...years); + const yearMax = Math.max(...years); + let optionMin = 0; + let optionMax = 0; + if (selectedOptions.quarter) { + const quarters = selectedOptions.quarter.map((o) => o.setParam.quarter); + if (globalGranularity === "month") { + delete selectedOptions.quarter; + for (const quarter of quarters) { + for (const month of dates.QUARTERS[quarter].coveredMonths) { + const monthOption = selectedOptions.month.find( + (o) => o.setParam.month === month + ); + if (!monthOption) { + selectedOptions.month.push({ + setParam: {month}, + granularity: "month", + }); + } + } + } + } else { + optionMin = Math.min(...quarters); + optionMax = Math.max(...quarters); + } + } + if (selectedOptions.month) { + const months = selectedOptions.month.map((o) => o.setParam.month); + optionMin = Math.min(...months); + optionMax = Math.max(...months); + } + if (selectedOptions.week) { + const weeks = selectedOptions.week.map((o) => o.setParam.weekNumber); + optionMin = Math.min(...weeks); + optionMax = Math.max(...weeks); + } + if (selectedOptions.day) { + const days = selectedOptions.day.map((o) => o.setParam.day); + optionMin = Math.min(...days); + optionMax = Math.max(...days); + } + const num = + -1 + granularityFactor * (yearMin - yearMax) + optionMin - optionMax; + const key = + globalGranularity === "year" + ? "years" + : globalGranularity === "month" + ? "months" + : globalGranularity === "week" + ? "weeks" + : globalGranularity === "day" + ? "days" + : "quarters"; + plusParam[key] = num; + return [plusParam, selectedOptions]; + }, +}); diff --git a/web_time_range_menu_custom/static/src/js/domain.js b/web_time_range_menu_custom/static/src/js/domain.js deleted file mode 100644 index 0972069cd..000000000 --- a/web_time_range_menu_custom/static/src/js/domain.js +++ /dev/null @@ -1,238 +0,0 @@ -/* 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(); - } - }, - }); -}); diff --git a/web_time_range_menu_custom/static/src/js/search_facet.js b/web_time_range_menu_custom/static/src/js/search_facet.js deleted file mode 100644 index 8f8c1d9dd..000000000 --- a/web_time_range_menu_custom/static/src/js/search_facet.js +++ /dev/null @@ -1,57 +0,0 @@ -/* 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); - }, - }); -}); diff --git a/web_time_range_menu_custom/static/src/js/time_range_menu.js b/web_time_range_menu_custom/static/src/js/time_range_menu.js deleted file mode 100644 index 90cb83519..000000000 --- a/web_time_range_menu_custom/static/src/js/time_range_menu.js +++ /dev/null @@ -1,140 +0,0 @@ -/* 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); - }, - }); -}); diff --git a/web_time_range_menu_custom/static/src/scss/web_time_range_menu_custom.scss b/web_time_range_menu_custom/static/src/scss/web_time_range_menu_custom.scss new file mode 100644 index 000000000..02bdb23ee --- /dev/null +++ b/web_time_range_menu_custom/static/src/scss/web_time_range_menu_custom.scss @@ -0,0 +1,8 @@ +#add_custom_period_wrapper { + padding: 0 20px; + white-space: nowrap; + .d-table-cell { + vertical-align: middle; + padding: 3px 0; + } +} diff --git a/web_time_range_menu_custom/static/src/xml/comparison_menu.xml b/web_time_range_menu_custom/static/src/xml/comparison_menu.xml new file mode 100644 index 000000000..e867032db --- /dev/null +++ b/web_time_range_menu_custom/static/src/xml/comparison_menu.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/web_time_range_menu_custom/static/src/xml/date_selector.xml b/web_time_range_menu_custom/static/src/xml/date_selector.xml new file mode 100644 index 000000000..5179ef839 --- /dev/null +++ b/web_time_range_menu_custom/static/src/xml/date_selector.xml @@ -0,0 +1,72 @@ + + + + + + + diff --git a/web_time_range_menu_custom/static/src/xml/filter_menu.xml b/web_time_range_menu_custom/static/src/xml/filter_menu.xml new file mode 100644 index 000000000..bc13917f3 --- /dev/null +++ b/web_time_range_menu_custom/static/src/xml/filter_menu.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/web_time_range_menu_custom/static/src/xml/time_range_menu.xml b/web_time_range_menu_custom/static/src/xml/time_range_menu.xml deleted file mode 100644 index 2837e6ec9..000000000 --- a/web_time_range_menu_custom/static/src/xml/time_range_menu.xml +++ /dev/null @@ -1,53 +0,0 @@ - - diff --git a/web_time_range_menu_custom/templates/assets.xml b/web_time_range_menu_custom/templates/assets.xml deleted file mode 100644 index e64bdd028..000000000 --- a/web_time_range_menu_custom/templates/assets.xml +++ /dev/null @@ -1,35 +0,0 @@ - - -