add all months in filter

This commit is contained in:
pawan.sharma 2022-08-22 12:50:07 +05:30
parent 8b537e13c9
commit ca20dfe016
4 changed files with 601 additions and 0 deletions

0
month_filter/__init__.py Normal file
View File

View File

@ -0,0 +1,15 @@
{
'name': 'Month Filter',
'version': '1.0.1',
'author': 'SunArc Technologies',
'website': 'www.sunarctechnologies.com',
'license': 'LGPL-3',
'depends': ['base','web'],
'data': [
'views/templates.xml'
],
'installable': True,
'auto_install': False,
}

View File

@ -0,0 +1,578 @@
odoo.define('web.searchUtils', function (require) {
"use strict";
const { _lt, _t } = require('web.core');
const Domain = require('web.Domain');
const pyUtils = require('web.py_utils');
//-------------------------------------------------------------------------
// Constants
//-------------------------------------------------------------------------
// Filter menu parameters
const FIELD_OPERATORS = {
boolean: [
{ symbol: "=", description: _lt("is true"), value: true },
{ symbol: "!=", description: _lt("is false"), value: true },
],
char: [
{ symbol: "ilike", description: _lt("contains") },
{ symbol: "not ilike", description: _lt("doesn't contain") },
{ symbol: "=", description: _lt("is equal to") },
{ symbol: "!=", description: _lt("is not equal to") },
{ symbol: "!=", description: _lt("is set"), value: false },
{ symbol: "=", description: _lt("is not set"), value: false },
],
date: [
{ symbol: "=", description: _lt("is equal to") },
{ symbol: "!=", description: _lt("is not equal to") },
{ symbol: ">", description: _lt("is after") },
{ symbol: "<", description: _lt("is before") },
{ symbol: ">=", description: _lt("is after or equal to") },
{ symbol: "<=", description: _lt("is before or equal to") },
{ symbol: "between", description: _lt("is between") },
{ symbol: "!=", description: _lt("is set"), value: false },
{ symbol: "=", description: _lt("is not set"), value: false },
],
datetime: [
{ symbol: "between", description: _lt("is between") },
{ symbol: "=", description: _lt("is equal to") },
{ symbol: "!=", description: _lt("is not equal to") },
{ symbol: ">", description: _lt("is after") },
{ symbol: "<", description: _lt("is before") },
{ symbol: ">=", description: _lt("is after or equal to") },
{ symbol: "<=", description: _lt("is before or equal to") },
{ symbol: "!=", description: _lt("is set"), value: false },
{ symbol: "=", description: _lt("is not set"), value: false },
],
id: [
{ symbol: "=", description: _lt("is") },
{ symbol: "<=", description: _lt("less than or equal to")},
{ symbol: ">", description: _lt("greater than")},
],
number: [
{ symbol: "=", description: _lt("is equal to") },
{ symbol: "!=", description: _lt("is not equal to") },
{ symbol: ">", description: _lt("greater than") },
{ symbol: "<", description: _lt("less than") },
{ symbol: ">=", description: _lt("greater than or equal to") },
{ symbol: "<=", description: _lt("less than or equal to") },
{ symbol: "!=", description: _lt("is set"), value: false },
{ symbol: "=", description: _lt("is not set"), value: false },
],
selection: [
{ symbol: "=", description: _lt("is") },
{ symbol: "!=", description: _lt("is not") },
{ symbol: "!=", description: _lt("is set"), value: false },
{ symbol: "=", description: _lt("is not set"), value: false },
],
};
const FIELD_TYPES = {
boolean: 'boolean',
char: 'char',
date: 'date',
datetime: 'datetime',
float: 'number',
id: 'id',
integer: 'number',
html: 'char',
many2many: 'char',
many2one: 'char',
monetary: 'number',
one2many: 'char',
text: 'char',
selection: 'selection',
};
const DEFAULT_PERIOD = 'this_month';
const QUARTERS = {
1: { description: _lt("Q1"), coveredMonths: [0, 1, 2] },
2: { description: _lt("Q2"), coveredMonths: [3, 4, 5] },
3: { description: _lt("Q3"), coveredMonths: [6, 7, 8] },
4: { description: _lt("Q4"), coveredMonths: [9, 10, 11] },
};
const MONTH_OPTIONS = {
this_month: {
id: 'this_month', groupNumber: 1, format: 'MMMM',
addParam: {}, granularity: 'month',
},
last_month: {
id: 'last_month', groupNumber: 1, format: 'MMMM',
addParam: { months: -1 }, granularity: 'month',
},
antepenultimate_month: {
id: 'antepenultimate_month', groupNumber: 1, format: 'MMMM',
addParam: { months: -2 }, granularity: 'month',
},
antepenultimate_month_3: {
id: 'antepenultimate_month_3', groupNumber: 1, format: 'MMMM',
addParam: { months: -3 }, granularity: 'month',
},
antepenultimate_month_4: {
id: 'antepenultimate_month_4', groupNumber: 1, format: 'MMMM',
addParam: { months: -4 }, granularity: 'month',
},
antepenultimate_month_5: {
id: 'antepenultimate_month_5', groupNumber: 1, format: 'MMMM',
addParam: { months: -5 }, granularity: 'month',
},
antepenultimate_month_6: {
id: 'antepenultimate_month_6', groupNumber: 1, format: 'MMMM',
addParam: { months: -6 }, granularity: 'month',
},
antepenultimate_month_7: {
id: 'antepenultimate_month_7', groupNumber: 1, format: 'MMMM',
addParam: { months: -7 }, granularity: 'month',
},
antepenultimate_month_8: {
id: 'antepenultimate_month_8', groupNumber: 1, format: 'MMMM',
addParam: { months: -8 }, granularity: 'month',
},
antepenultimate_month_9: {
id: 'antepenultimate_month_9', groupNumber: 1, format: 'MMMM',
addParam: { months: -9 }, granularity: 'month',
},
antepenultimate_month_10: {
id: 'antepenultimate_month_10', groupNumber: 1, format: 'MMMM',
addParam: { months: -10 }, granularity: 'month',
},
antepenultimate_month_11: {
id: 'antepenultimate_month_11', groupNumber: 1, format: 'MMMM',
addParam: { months: -11 }, granularity: 'month',
},
};
const QUARTER_OPTIONS = {
fourth_quarter: {
id: 'fourth_quarter', groupNumber: 1, description: QUARTERS[4].description,
setParam: { quarter: 4 }, granularity: 'quarter',
},
third_quarter: {
id: 'third_quarter', groupNumber: 1, description: QUARTERS[3].description,
setParam: { quarter: 3 }, granularity: 'quarter',
},
second_quarter: {
id: 'second_quarter', groupNumber: 1, description: QUARTERS[2].description,
setParam: { quarter: 2 }, granularity: 'quarter',
},
first_quarter: {
id: 'first_quarter', groupNumber: 1, description: QUARTERS[1].description,
setParam: { quarter: 1 }, granularity: 'quarter',
},
};
const YEAR_OPTIONS = {
this_year: {
id: 'this_year', groupNumber: 2, format: 'YYYY',
addParam: {}, granularity: 'year',
},
last_year: {
id: 'last_year', groupNumber: 2, format: 'YYYY',
addParam: { years: -1 }, granularity: 'year',
},
antepenultimate_year: {
id: 'antepenultimate_year', groupNumber: 2, format: 'YYYY',
addParam: { years: -2 }, granularity: 'year',
},
};
const PERIOD_OPTIONS = Object.assign({}, MONTH_OPTIONS, QUARTER_OPTIONS, YEAR_OPTIONS);
// GroupBy menu parameters
const GROUPABLE_TYPES = [
'boolean',
'char',
'date',
'datetime',
'integer',
'many2one',
'selection',
];
const DEFAULT_INTERVAL = 'month';
const INTERVAL_OPTIONS = {
year: { description: _lt("Year"), id: 'year', groupNumber: 1 },
quarter: { description: _lt("Quarter"), id: 'quarter', groupNumber: 1 },
month: { description: _lt("Month"), id: 'month', groupNumber: 1 },
week: { description: _lt("Week"), id: 'week', groupNumber: 1 },
day: { description: _lt("Day"), id: 'day', groupNumber: 1 }
};
// Comparison menu parameters
const COMPARISON_OPTIONS = {
previous_period: {
description: _lt("Previous Period"), id: 'previous_period',
},
previous_year: {
description: _lt("Previous Year"), id: 'previous_year', addParam: { years: -1 },
},
};
const PER_YEAR = {
year: 1,
quarter: 4,
month: 12,
};
// Search bar
const FACET_ICONS = {
filter: 'fa fa-filter',
groupBy: 'fa fa-bars',
favorite: 'fa fa-star',
comparison: 'fa fa-adjust',
};
//-------------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------------
/**
* Constructs the string representation of a domain and its description. The
* domain is of the form:
* ['|',..., '|', d_1,..., d_n]
* where d_i is a time range of the form
* ['&', [fieldName, >=, leftBound_i], [fieldName, <=, rightBound_i]]
* where leftBound_i and rightBound_i are date or datetime computed accordingly
* to the given options and reference moment.
* (@see constructDateRange).
* @param {moment} referenceMoment
* @param {string} fieldName
* @param {string} fieldType
* @param {string[]} selectedOptionIds
* @param {string} [comparisonOptionId]
* @returns {{ domain: string, description: string }}
*/
function constructDateDomain(
referenceMoment,
fieldName,
fieldType,
selectedOptionIds,
comparisonOptionId
) {
let addParam;
let selectedOptions;
if (comparisonOptionId) {
[addParam, selectedOptions] = getComparisonParams(
referenceMoment,
selectedOptionIds,
comparisonOptionId);
} else {
selectedOptions = getSelectedOptions(referenceMoment, selectedOptionIds);
}
const yearOptions = selectedOptions.year;
const otherOptions = [
...(selectedOptions.quarter || []),
...(selectedOptions.month || [])
];
sortPeriodOptions(yearOptions);
sortPeriodOptions(otherOptions);
const ranges = [];
for (const yearOption of yearOptions) {
const constructRangeParams = {
referenceMoment,
fieldName,
fieldType,
addParam,
};
if (otherOptions.length) {
for (const option of otherOptions) {
const setParam = Object.assign({},
yearOption.setParam,
option ? option.setParam : {}
);
const { granularity } = option;
const range = constructDateRange(Object.assign(
{ granularity, setParam },
constructRangeParams
));
ranges.push(range);
}
} else {
const { granularity, setParam } = yearOption;
const range = constructDateRange(Object.assign(
{ granularity, setParam },
constructRangeParams
));
ranges.push(range);
}
}
const domain = pyUtils.assembleDomains(ranges.map(range => range.domain), 'OR');
const description = ranges.map(range => range.description).join("/");
return { domain, description };
}
/**
* Constructs the string representation of a domain and its description. The
* domain is a time range of the form:
* ['&', [fieldName, >=, leftBound],[fieldName, <=, rightBound]]
* where leftBound and rightBound are some date or datetime determined by setParam,
* addParam, granularity and the reference moment.
* @param {Object} params
* @param {moment} params.referenceMoment
* @param {string} params.fieldName
* @param {string} params.fieldType
* @param {string} params.granularity
* @param {Object} params.setParam
* @param {Object} [params.addParam]
* @returns {{ domain: string, description: string }}
*/
function constructDateRange({
referenceMoment,
fieldName,
fieldType,
granularity,
setParam,
addParam,
}) {
const date = referenceMoment.clone().set(setParam).add(addParam || {});
// compute domain
let leftBound = date.clone().locale('en').startOf(granularity);
let rightBound = date.clone().locale('en').endOf(granularity);
if (fieldType === 'date') {
leftBound = leftBound.format('YYYY-MM-DD');
rightBound = rightBound.format('YYYY-MM-DD');
} else {
leftBound = leftBound.utc().format('YYYY-MM-DD HH:mm:ss');
rightBound = rightBound.utc().format('YYYY-MM-DD HH:mm:ss');
}
const domain = Domain.prototype.arrayToString([
'&',
[fieldName, '>=', leftBound],
[fieldName, '<=', rightBound]
]);
// compute description
const descriptions = [date.format("YYYY")];
const method = _t.database.parameters.direction === "rtl" ? "push" : "unshift";
if (granularity === "month") {
descriptions[method](date.format("MMMM"));
} else if (granularity === "quarter") {
descriptions[method](QUARTERS[date.quarter()].description);
}
const description = descriptions.join(" ");
return { domain, description, };
}
/**
* Returns a version of the options in COMPARISON_OPTIONS with translated descriptions.
* @see getOptionsWithDescriptions
*/
function getComparisonOptions() {
return getOptionsWithDescriptions(COMPARISON_OPTIONS);
}
/**
* Returns the params addParam and selectedOptions necessary for the computation
* of a comparison domain.
* @param {moment} referenceMoment
* @param {string{}} selectedOptionIds
* @param {string} comparisonOptionId
* @returns {Object[]}
*/
function getComparisonParams(referenceMoment, selectedOptionIds, comparisonOptionId) {
const comparisonOption = COMPARISON_OPTIONS[comparisonOptionId];
const selectedOptions = getSelectedOptions(referenceMoment, selectedOptionIds);
let addParam = comparisonOption.addParam;
if (addParam) {
return [addParam, selectedOptions];
}
addParam = {};
let globalGranularity = 'year';
if (selectedOptions.month) {
globalGranularity = 'month';
} else if (selectedOptions.quarter) {
globalGranularity = 'quarter';
}
const granularityFactor = 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 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);
}
addParam[globalGranularity] = -1 +
granularityFactor * (yearMin - yearMax) +
optionMin - optionMax;
return [addParam, selectedOptions];
}
/**
* Returns a version of the options in INTERVAL_OPTIONS with translated descriptions.
* @see getOptionsWithDescriptions
*/
function getIntervalOptions() {
return getOptionsWithDescriptions(INTERVAL_OPTIONS);
}
/**
* Returns a version of the options in PERIOD_OPTIONS with translated descriptions
* and a key defautlYearId used in the control panel model when toggling a period option.
* @param {moment} referenceMoment
* @returns {Object[]}
*/
function getPeriodOptions(referenceMoment) {
const options = [];
for (const option of Object.values(PERIOD_OPTIONS)) {
const { id, groupNumber, description, } = option;
const res = { id, groupNumber, };
const date = referenceMoment.clone().set(option.setParam).add(option.addParam);
if (description) {
res.description = description.toString();
} else {
res.description = date.format(option.format.toString());
}
res.setParam = getSetParam(option, referenceMoment);
res.defaultYear = date.year();
options.push(res);
}
for (const option of options) {
const yearOption = options.find(
o => o.setParam && o.setParam.year === option.defaultYear
);
option.defaultYearId = yearOption.id;
delete option.defaultYear;
delete option.setParam;
}
return options;
}
/**
* Returns a version of the options in OPTIONS with translated descriptions (if any).
* @param {Object{}} OPTIONS
* @returns {Object[]}
*/
function getOptionsWithDescriptions(OPTIONS) {
const options = [];
for (const option of Object.values(OPTIONS)) {
const { id, groupNumber, description, } = option;
const res = { id, };
if (description) {
res.description = description.toString();
}
if (groupNumber) {
res.groupNumber = groupNumber;
}
options.push(res);
}
return options;
}
/**
* Returns a version of the period options whose ids are in selectedOptionIds
* partitioned by granularity.
* @param {moment} referenceMoment
* @param {string[]} selectedOptionIds
* @param {Object}
*/
function getSelectedOptions(referenceMoment, selectedOptionIds) {
const selectedOptions = { year: [] };
for (const optionId of selectedOptionIds) {
const option = PERIOD_OPTIONS[optionId];
const setParam = getSetParam(option, referenceMoment);
const granularity = option.granularity;
if (!selectedOptions[granularity]) {
selectedOptions[granularity] = [];
}
selectedOptions[granularity].push({ granularity, setParam });
}
return selectedOptions;
}
/**
* Returns the setParam object associated with the given periodOption and
* referenceMoment.
* @param {Object} periodOption
* @param {moment} referenceMoment
* @returns {Object}
*/
function getSetParam(periodOption, referenceMoment) {
if (periodOption.setParam) {
return periodOption.setParam;
}
const date = referenceMoment.clone().add(periodOption.addParam);
const setParam = {};
setParam[periodOption.granularity] = date[periodOption.granularity]();
return setParam;
}
/**
* @param {string} intervalOptionId
* @returns {number} index
*/
function rankInterval(intervalOptionId) {
return Object.keys(INTERVAL_OPTIONS).indexOf(intervalOptionId);
}
/**
* Sorts in place an array of 'period' options.
* @param {Object[]} options supposed to be of the form:
* { granularity, setParam, }
*/
function sortPeriodOptions(options) {
options.sort((o1, o2) => {
const granularity1 = o1.granularity;
const granularity2 = o2.granularity;
if (granularity1 === granularity2) {
return o1.setParam[granularity1] - o2.setParam[granularity1];
}
return granularity1 < granularity2 ? -1 : 1;
});
}
/**
* Checks if a year id is among the given array of period option ids.
* @param {string[]} selectedOptionIds
* @returns {boolean}
*/
function yearSelected(selectedOptionIds) {
return selectedOptionIds.some(optionId => !!YEAR_OPTIONS[optionId]);
}
return {
COMPARISON_OPTIONS,
DEFAULT_INTERVAL,
DEFAULT_PERIOD,
FACET_ICONS,
FIELD_OPERATORS,
FIELD_TYPES,
GROUPABLE_TYPES,
INTERVAL_OPTIONS,
PERIOD_OPTIONS,
constructDateDomain,
getComparisonOptions,
getIntervalOptions,
getPeriodOptions,
rankInterval,
yearSelected,
};
});

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<template id="filter_extend_assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/month_filter/static/src/js/control_panel/custom_search_utils.js"/>
</xpath>
</template>
</odoo>