Files
web/web_time_range_menu_custom/static/src/js/dates.esm.js

360 lines
13 KiB
JavaScript

/** @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 date = referenceMoment.set(setParam).plus(plusParam || {});
// Compute domain
var leftDate = date.startOf(granularity);
var rightDate = date.endOf(granularity);
if (
custom_period.is_custom_period &&
parseInt(custom_period.last_period) !== 0
) {
if (granularity === "day") {
const plusParamReferenceMoment = referenceMoment.plus(plusParam || {});
leftDate = leftDate.plus({days: 1});
rightDate = plusParamReferenceMoment;
} else {
var customPlusParam = {};
customPlusParam[granularity + "s"] = parseInt(
custom_period.last_period
);
rightDate = leftDate.plus(customPlusParam);
}
}
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];
},
});