[IMP] spreadsheet: add date from_to global filter
Adds in date type global filters a new category "From / To" allowing to define a domain between two dates. closes odoo/odoo#138507 Task: 3516362 Related: odoo/enterprise#48855 Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
This commit is contained in:
committed by
Lucas Lefèvre (lul)
parent
005b76462a
commit
c0bc8d9ea9
+40
@@ -0,0 +1,40 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { Component } from "@odoo/owl";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { DateTimeInput } from "@web/core/datetime/datetime_input";
|
||||
import { serializeDate, deserializeDate } from "@web/core/l10n/dates";
|
||||
|
||||
export class DateFromToValue extends Component {
|
||||
static template = "spreadsheet.DateFromToValue";
|
||||
static components = { DateTimeInput };
|
||||
static props = {
|
||||
onFromToChanged: Function,
|
||||
from: { type: String, optional: true },
|
||||
to: { type: String, optional: true },
|
||||
};
|
||||
fromPlaceholder = _t("Date from...");
|
||||
toPlaceholder = _t("Date to...");
|
||||
|
||||
onDateFromChanged(dateFrom) {
|
||||
this.props.onFromToChanged({
|
||||
from: dateFrom && serializeDate(dateFrom.startOf("day")),
|
||||
to: this.props.to,
|
||||
});
|
||||
}
|
||||
|
||||
onDateToChanged(dateTo) {
|
||||
this.props.onFromToChanged({
|
||||
from: this.props.from,
|
||||
to: dateTo && serializeDate(dateTo.endOf("day")),
|
||||
});
|
||||
}
|
||||
|
||||
get dateFrom() {
|
||||
return this.props.from && deserializeDate(this.props.from);
|
||||
}
|
||||
|
||||
get dateTo() {
|
||||
return this.props.to && deserializeDate(this.props.to);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<templates>
|
||||
<div t-name="spreadsheet.DateFromToValue" class="date_filter_values">
|
||||
<DateTimeInput
|
||||
value="dateFrom"
|
||||
type="'date'"
|
||||
placeholder="fromPlaceholder"
|
||||
onChange.bind="onDateFromChanged"
|
||||
/>
|
||||
<i class="oi oi-arrow-right"></i>
|
||||
<DateTimeInput
|
||||
value="dateTo"
|
||||
type="'date'"
|
||||
placeholder="toPlaceholder"
|
||||
onChange.bind="onDateToChanged"
|
||||
/>
|
||||
</div>
|
||||
</templates>
|
||||
+2
-1
@@ -3,6 +3,7 @@
|
||||
import { MultiRecordSelector } from "@web/core/record_selectors/multi_record_selector";
|
||||
import { RELATIVE_DATE_RANGE_TYPES } from "@spreadsheet/helpers/constants";
|
||||
import { DateFilterValue } from "../filter_date_value/filter_date_value";
|
||||
import { DateFromToValue } from "../filter_date_from_to_value/filter_date_from_to_value";
|
||||
|
||||
import { Component } from "@odoo/owl";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
@@ -48,7 +49,7 @@ export class FilterValue extends Component {
|
||||
}
|
||||
}
|
||||
FilterValue.template = "spreadsheet_edition.FilterValue";
|
||||
FilterValue.components = { DateFilterValue, MultiRecordSelector };
|
||||
FilterValue.components = { DateFilterValue, DateFromToValue, MultiRecordSelector };
|
||||
FilterValue.props = {
|
||||
filter: Object,
|
||||
model: Object,
|
||||
|
||||
@@ -7,4 +7,9 @@
|
||||
.o_datepicker_input {
|
||||
color: $o-main-text-color;
|
||||
}
|
||||
.date_filter_values {
|
||||
display: flex;
|
||||
gap: map-get($spacers, 2);
|
||||
align-items: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
+13
-7
@@ -2,9 +2,10 @@
|
||||
<templates>
|
||||
<t t-name="spreadsheet_edition.FilterValue"
|
||||
>
|
||||
<div class="o-filter-value d-flex align-items-start w-100">
|
||||
<t t-set="filter"
|
||||
t-value="props.filter"/>
|
||||
<t t-set="filter"
|
||||
t-value="props.filter"/>
|
||||
<div class="o-filter-value d-flex align-items-start w-100"
|
||||
t-att-class="filter.rangeType === 'from_to' ? 'o-filter-value-double-size':''">
|
||||
<t t-set="filterValue"
|
||||
t-value="getters.getGlobalFilterValue(filter.id) || []"/>
|
||||
<div t-if="filter.type === 'text'" class="w-100">
|
||||
@@ -22,10 +23,6 @@
|
||||
update="(resIds) => this.onTagSelected(filter.id, resIds)" />
|
||||
</span>
|
||||
<div t-if="filter.type === 'date'" class="w-100">
|
||||
<DateFilterValue t-if="filter.rangeType !== 'relative'"
|
||||
period="filterValue && filterValue.period"
|
||||
yearOffset="filterValue && filterValue.yearOffset"
|
||||
onTimeRangeChanged="(value) => this.onDateInput(filter.id, value)" />
|
||||
<select t-if="filter.rangeType === 'relative'"
|
||||
t-on-change="(e) => this.onDateInput(filter.id, e.target.value || undefined)"
|
||||
class="date_filter_values o_input me-3"
|
||||
@@ -40,6 +37,15 @@
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
<DateFromToValue t-elif="filter.rangeType === 'from_to'"
|
||||
from="filterValue?.from"
|
||||
to="filterValue?.to"
|
||||
onFromToChanged="(value) => this.onDateInput(filter.id, value)"/>
|
||||
|
||||
<DateFilterValue t-else=""
|
||||
period="filterValue?.period"
|
||||
yearOffset="filterValue?.yearOffset"
|
||||
onTimeRangeChanged="(value) => this.onDateInput(filter.id, value)"/>
|
||||
</div>
|
||||
<i t-if="getters.isGlobalFilterActive(filter.id)"
|
||||
class="fa fa-times btn btn-link text-muted o_side_panel_filter_icon ms-1"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** @odoo-module */
|
||||
|
||||
/**
|
||||
* @typedef {"fixedPeriod"|"relative"} RangeType
|
||||
* @typedef {"fixedPeriod"|"relative"|"from_to"} RangeType
|
||||
*
|
||||
* @typedef {"last_month" | "last_week" | "last_year" | "last_three_years" | "this_month" | "this_quarter" | "this_year"} RelativePeriod
|
||||
*
|
||||
|
||||
@@ -163,6 +163,9 @@ export class GlobalFiltersUIPlugin extends spreadsheet.UIPlugin {
|
||||
|
||||
const value = filterId in this.values ? this.values[filterId].value : undefined;
|
||||
const preventAutomaticValue = this.values[filterId]?.value?.preventAutomaticValue;
|
||||
if (filter.type === "date" && filter.rangeType === "from_to") {
|
||||
return value || { from: undefined, to: undefined };
|
||||
}
|
||||
const defaultValue = (!preventAutomaticValue && filter.defaultValue) || undefined;
|
||||
if (filter.type === "date" && preventAutomaticValue) {
|
||||
return undefined;
|
||||
@@ -193,7 +196,11 @@ export class GlobalFiltersUIPlugin extends spreadsheet.UIPlugin {
|
||||
case "date":
|
||||
return (
|
||||
value &&
|
||||
(typeof value === "string" || value.yearOffset !== undefined || value.period)
|
||||
(typeof value === "string" ||
|
||||
value.yearOffset !== undefined ||
|
||||
value.period ||
|
||||
value.from ||
|
||||
value.to)
|
||||
);
|
||||
case "relation":
|
||||
return value && value.length;
|
||||
@@ -315,7 +322,7 @@ export class GlobalFiltersUIPlugin extends spreadsheet.UIPlugin {
|
||||
value = "";
|
||||
break;
|
||||
case "date":
|
||||
value = { yearOffset: undefined, preventAutomaticValue: true };
|
||||
value = { preventAutomaticValue: true };
|
||||
break;
|
||||
case "relation":
|
||||
value = { preventAutomaticValue: true };
|
||||
@@ -349,6 +356,19 @@ export class GlobalFiltersUIPlugin extends spreadsheet.UIPlugin {
|
||||
const offset = fieldMatching.offset || 0;
|
||||
const now = DateTime.local();
|
||||
|
||||
if (filter.rangeType === "from_to") {
|
||||
if (value.from && value.to) {
|
||||
return new Domain(["&", [field, ">=", value.from], [field, "<=", value.to]]);
|
||||
}
|
||||
if (value.from) {
|
||||
return new Domain([[field, ">=", value.from]]);
|
||||
}
|
||||
if (value.to) {
|
||||
return new Domain([[field, "<=", value.to]]);
|
||||
}
|
||||
return new Domain();
|
||||
}
|
||||
|
||||
if (filter.rangeType === "relative") {
|
||||
return getRelativeDateDomain(now, offset, value, field, type);
|
||||
}
|
||||
|
||||
@@ -1173,6 +1173,24 @@ QUnit.module("spreadsheet > Global filters model", {}, () => {
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Date filter automatic undefined values for from_to filter",
|
||||
async function (assert) {
|
||||
const label = "From to";
|
||||
const { model } = await createSpreadsheetWithPivot();
|
||||
await addGlobalFilter(model, {
|
||||
id: "1",
|
||||
type: "date",
|
||||
label,
|
||||
rangeType: "from_to",
|
||||
});
|
||||
assert.deepEqual(model.getters.getGlobalFilterValue("1"), {
|
||||
from: undefined,
|
||||
to: undefined,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("Date filter automatic default value at model loading", async function (assert) {
|
||||
const label = "This year";
|
||||
const model = new Model({
|
||||
@@ -1317,6 +1335,122 @@ QUnit.module("spreadsheet > Global filters model", {}, () => {
|
||||
assertDateDomainEqual(assert, "date", "2016-05-18", "2019-05-17", computedDomain);
|
||||
});
|
||||
|
||||
QUnit.test("from_to date filter at model loading", async function (assert) {
|
||||
const model = new Model({
|
||||
globalFilters: [
|
||||
{ type: "date", rangeType: "from_to", label: "From To", fields: {}, id: "1" },
|
||||
],
|
||||
});
|
||||
assert.deepEqual(model.getters.getGlobalFilterValue("1"), {
|
||||
from: undefined,
|
||||
to: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("from_to date filter domain value", async function (assert) {
|
||||
const { model } = await createSpreadsheetWithPivot();
|
||||
/**@type GlobalFilter */
|
||||
const filter = {
|
||||
id: "42",
|
||||
type: "date",
|
||||
label: "From To",
|
||||
rangeType: "from_to",
|
||||
};
|
||||
const value = {
|
||||
from: "2022-01-01",
|
||||
to: "2022-05-16",
|
||||
};
|
||||
await addGlobalFilter(model, filter, { pivot: { 1: { chain: "date", type: "date" } } });
|
||||
await setGlobalFilterValue(model, { id: "42", value });
|
||||
const computedDomain = model.getters.getPivotComputedDomain("1");
|
||||
assertDateDomainEqual(assert, "date", "2022-01-01", "2022-05-16", computedDomain);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"set 'from_to' date filter domain value from specific date --> to specific date",
|
||||
async function (assert) {
|
||||
const { model } = await createSpreadsheetWithPivot();
|
||||
/**@type GlobalFilter */
|
||||
const filter = {
|
||||
id: "42",
|
||||
type: "date",
|
||||
label: "From To",
|
||||
rangeType: "from_to",
|
||||
};
|
||||
const value = {
|
||||
from: "2022-01-01",
|
||||
to: "2022-05-16",
|
||||
};
|
||||
await addGlobalFilter(model, filter, { pivot: { 1: { chain: "date", type: "date" } } });
|
||||
await setGlobalFilterValue(model, { id: "42", value });
|
||||
const computedDomain = model.getters.getPivotComputedDomain("1");
|
||||
assertDateDomainEqual(assert, "date", "2022-01-01", "2022-05-16", computedDomain);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"set 'from_to' date filter domain value from specific date",
|
||||
async function (assert) {
|
||||
const { model } = await createSpreadsheetWithPivot();
|
||||
/**@type GlobalFilter */
|
||||
const filter = {
|
||||
id: "42",
|
||||
type: "date",
|
||||
label: "From To",
|
||||
rangeType: "from_to",
|
||||
};
|
||||
const value = {
|
||||
from: "2022-01-01",
|
||||
to: undefined,
|
||||
};
|
||||
await addGlobalFilter(model, filter, { pivot: { 1: { chain: "date", type: "date" } } });
|
||||
await setGlobalFilterValue(model, { id: "42", value });
|
||||
const computedDomain = model.getters.getPivotComputedDomain("1");
|
||||
assert.deepEqual(computedDomain, [["date", ">=", "2022-01-01"]]);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("set 'from_to' date filter domain value to specific date", async function (assert) {
|
||||
const { model } = await createSpreadsheetWithPivot();
|
||||
/**@type GlobalFilter */
|
||||
const filter = {
|
||||
id: "42",
|
||||
type: "date",
|
||||
label: "From To",
|
||||
rangeType: "from_to",
|
||||
};
|
||||
const value = {
|
||||
from: undefined,
|
||||
to: "2022-05-16",
|
||||
};
|
||||
await addGlobalFilter(model, filter, { pivot: { 1: { chain: "date", type: "date" } } });
|
||||
await setGlobalFilterValue(model, { id: "42", value });
|
||||
const computedDomain = model.getters.getPivotComputedDomain("1");
|
||||
assert.deepEqual(computedDomain, [["date", "<=", "2022-05-16"]]);
|
||||
});
|
||||
|
||||
QUnit.test("can clear 'from_to' date filter values", async function (assert) {
|
||||
const { model } = await createSpreadsheetWithPivot();
|
||||
await addGlobalFilter(model, {
|
||||
id: "42",
|
||||
type: "date",
|
||||
label: "From To",
|
||||
rangeType: "from_to",
|
||||
});
|
||||
const [filter] = model.getters.getGlobalFilters();
|
||||
const value = {
|
||||
from: "2022-01-01",
|
||||
to: "2022-05-16",
|
||||
};
|
||||
await setGlobalFilterValue(model, { id: "42", value });
|
||||
model.dispatch("CLEAR_GLOBAL_FILTER_VALUE", { id: filter.id });
|
||||
assert.deepEqual(
|
||||
model.getters.getGlobalFilterValue(filter.id),
|
||||
{ preventAutomaticValue: true },
|
||||
"can clear 'from_to' date filter values"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Can set a value to a relation filter from the SET_MANY_GLOBAL_FILTER_VALUE command",
|
||||
async function (assert) {
|
||||
|
||||
+5
-5
@@ -67,16 +67,16 @@
|
||||
.o-filter-value {
|
||||
min-height: 25px;
|
||||
min-width: 100px;
|
||||
flex-basis: 100px;
|
||||
flex-grow: 1;
|
||||
|
||||
.o_multi_record_selector {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.date_filter_values {
|
||||
display: flex;
|
||||
gap: map-get($spacers, 2);
|
||||
align-items: baseline;
|
||||
}
|
||||
.o-filter-value-double-size {
|
||||
flex-basis: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user