Initial commit: Odoo 18.0-20251222 extra-addons
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
tests / Detect unreleased dependencies (push) Has been cancelled
tests / test with OCB (push) Has been cancelled
tests / test with Odoo (push) Has been cancelled

This commit is contained in:
tocmo0nlord
2026-03-13 20:43:25 +00:00
parent 36e847a7df
commit adbe430761
9472 changed files with 1265727 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -0,0 +1,502 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Date Range</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="date-range">
<h1 class="title">Date Range</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:26156f1d5b0f8d700a7fa2a8a81ce509bfa25d8eb261aefc72986f03e59ee04a
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Mature" src="https://img.shields.io/badge/maturity-Mature-brightgreen.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/server-ux/tree/18.0/date_range"><img alt="OCA/server-ux" src="https://img.shields.io/badge/github-OCA%2Fserver--ux-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/server-ux-18-0/server-ux-18-0-date_range"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/server-ux&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module lets you define global date ranges that can be used to
filter your values in tree views.</p>
<p>It also provides a mixin model for developers that extends the models
search view so that date ranges can be search as any relational field.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-2">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-3">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-8">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="installation">
<h1><a class="toc-backref" href="#toc-entry-1">Installation</a></h1>
<p>The addon use the daterange method from postgres. This method is
supported as of postgresql 9.2</p>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-2">Configuration</a></h1>
<p>For regular usage, see Usage below. This section is to clarify optional
functionality to developers.</p>
<p>To configure a model to use the Many2one style search field, make the
model inherit from `date.range.search.mixin`:</p>
<pre class="literal-block">
class AccountMove(models.Model):
_name = &quot;account.move&quot;
_inherit = [&quot;account.move&quot;, &quot;date.range.search.mixin&quot;]
</pre>
<p>This will make a Period field show up in the search view:</p>
<blockquote>
<img alt="search_view" src="https://raw.githubusercontent.com/OCA/server-ux/18.0/date_range/static/description/date_range_many2one_search_field.png" /></blockquote>
<p>By default, the mixin works on the date field. If you want the mixin to
work on a field with a different name, you can set a property on your
model:</p>
<pre class="literal-block">
_date_range_search_field = &quot;invoice_date&quot;
</pre>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-3">Usage</a></h1>
<p>To configure this module, you need to:</p>
<ul>
<li><p class="first">Go to Settings &gt; Technical &gt; Date ranges &gt; Date Range Types where you
can create types of date ranges.</p>
<p><img alt="image1" src="https://raw.githubusercontent.com/OCA/server-ux/18.0/date_range/static/description/date_range_type_create.png" /></p>
</li>
<li><p class="first">Go to Settings &gt; Technical &gt; Date ranges &gt; Date Ranges where you can
create date ranges.</p>
<p><img alt="image2" src="https://raw.githubusercontent.com/OCA/server-ux/18.0/date_range/static/description/date_range_create.png" /></p>
<p>Its also possible to launch a wizard from the Generate Date Ranges
menu.</p>
<p><img alt="image3" src="https://raw.githubusercontent.com/OCA/server-ux/18.0/date_range/static/description/date_range_wizard.png" /></p>
<p>The wizard is useful to generate recurring periods. Set an end date
or enter the number of ranges to create.</p>
<p><img alt="image4" src="https://raw.githubusercontent.com/OCA/server-ux/18.0/date_range/static/description/date_range_wizard_result.png" /></p>
</li>
<li><p class="first">Your date ranges are now available in the search filter for any date
or datetime fields</p>
<p>Date range types are proposed as a filter operator</p>
<p><img alt="image5" src="https://raw.githubusercontent.com/OCA/server-ux/18.0/date_range/static/description/date_range_type_as_filter.png" /></p>
<p>Once a type is selected, date ranges of this type are porposed as a
filter value</p>
<p><img alt="image6" src="https://raw.githubusercontent.com/OCA/server-ux/18.0/date_range/static/description/date_range_as_filter.png" /></p>
<p>And the dates specified into the date range are used to filter your
result.</p>
<p><img alt="image7" src="https://raw.githubusercontent.com/OCA/server-ux/18.0/date_range/static/description/date_range_as_filter_result.png" /></p>
</li>
<li><p class="first">You can configure date range types with default values for the
generation wizard on the Generation tab. In the same tab you can also
configure date range types for auto-generation. New ranges for types
configured for this are generated by a scheduled task that runs
daily.</p>
<p><img alt="image8" src="https://raw.githubusercontent.com/OCA/server-ux/18.0/date_range/static/description/date_range_type_autogeneration.png" /></p>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-4">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/server-ux/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/server-ux/issues/new?body=module:%20date_range%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-5">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-6">Authors</a></h2>
<ul class="simple">
<li>ACSONE SA/NV</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<ul class="simple">
<li>Laurent Mignon &lt;<a class="reference external" href="mailto:laurent.mignon&#64;acsone.eu">laurent.mignon&#64;acsone.eu</a>&gt;</li>
<li>Alexis de Lattre &lt;<a class="reference external" href="mailto:alexis.delattre&#64;akretion.com">alexis.delattre&#64;akretion.com</a>&gt;</li>
<li>Miquel Raïch &lt;<a class="reference external" href="mailto:miquel.raich&#64;forgeflow.com">miquel.raich&#64;forgeflow.com</a>&gt;</li>
<li>Andrea Stirpe &lt;<a class="reference external" href="mailto:a.stirpe&#64;onestein.nl">a.stirpe&#64;onestein.nl</a>&gt;</li>
<li>Stefan Rijnhart &lt;<a class="reference external" href="mailto:stefan&#64;opener.amsterdam">stefan&#64;opener.amsterdam</a>&gt;</li>
<li>David Ramia &lt;&lt;&#64;ramiadavid&gt;&gt;</li>
<li>Son Ho &lt;<a class="reference external" href="mailto:sonhd&#64;trobz.com">sonhd&#64;trobz.com</a>&gt;</li>
<li>Bert Van Groenendael &lt;<a class="reference external" href="mailto:bert.vangroenendael&#64;dynapps.eu">bert.vangroenendael&#64;dynapps.eu</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external image-reference" href="https://github.com/lmignon"><img alt="lmignon" src="https://github.com/lmignon.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/server-ux/tree/18.0/date_range">OCA/server-ux</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,96 @@
/* global document */
import {
condition,
connector,
domainFromTree,
formatValue,
normalizeValue,
treeFromDomain,
} from "@web/core/tree_editor/condition_tree";
function addChild(parent, child) {
if (child.type === "connector" && !child.negate && child.value === parent.value) {
parent.children.push(...child.children);
} else {
parent.children.push(child);
}
}
export function removeDateRangeOperators(tree) {
if (tree.type === "complex_condition") {
return tree;
}
if (tree.type === "condition") {
if (!tree.operator.includes("daterange")) {
return tree;
}
const {negate, path, value} = tree;
return connector(
"&",
[condition(path, "<=", value[0]), condition(path, ">=", value[1])],
negate
);
}
const processedChildren = tree.children.map(removeDateRangeOperators);
if (tree.value === "|") {
return {...tree, children: processedChildren};
}
const newTree = {...tree, children: []};
// After processing a child might have become a connector "&" --> normalize
for (let i = 0; i < processedChildren.length; i++) {
addChild(newTree, processedChildren[i]);
}
return newTree;
}
function createDateRangeOperators(tree) {
if (["condition", "complex_condition"].includes(tree.type)) {
return tree;
}
const processedChildren = tree.children.map(createDateRangeOperators);
if (tree.value === "|") {
return {...tree, children: processedChildren};
}
const children = [];
let operator = "daterange";
if (document.getElementsByTagName("select").length) {
operator = document
.getElementsByTagName("select")[0]
.selectedOptions[0].value.replace(/^"|"$/g, "");
}
for (let i = 0; i < processedChildren.length; i++) {
const child1 = processedChildren[i];
const child2 = processedChildren[i + 1];
if (
child1.type === "condition" &&
child2 &&
child2.type === "condition" &&
formatValue(child1.path) === formatValue(child2.path) &&
child1.operator === "<=" &&
child2.operator === ">="
) {
children.push(
condition(
child1.path,
operator,
normalizeValue([child1.value, child2.value])
)
);
i += 1;
} else {
children.push(child1);
}
}
if (children.length === 1) {
return {...children[0]};
}
return {...tree, children};
}
export function domainFromTreeDateRange(tree) {
return domainFromTree(removeDateRangeOperators(tree));
}
export function treeFromDomainDateRange(domain, options = {}) {
return createDateRangeOperators(treeFromDomain(domain, options));
}

View File

@@ -0,0 +1,107 @@
import {domainFromTreeDateRange, treeFromDomainDateRange} from "./condition_tree.esm";
import {onWillStart, useChildSubEnv} from "@odoo/owl";
import {Domain} from "@web/core/domain";
import {DomainSelector} from "@web/core/domain_selector/domain_selector";
import {patch} from "@web/core/utils/patch";
import {treeFromDomain} from "@web/core/tree_editor/condition_tree";
import {useService} from "@web/core/utils/hooks";
const ARCHIVED_DOMAIN = `[("active", "in", [True, False])]`;
patch(DomainSelector.prototype, {
setup() {
super.setup();
this.orm = useService("orm");
this.dateRanges = [];
this.dateRangeTypes = [];
useChildSubEnv({domain: this});
onWillStart(async () => {
this.dateRanges = await this.orm.call("date.range", "search_read", []);
this.dateRangeTypes = await this.orm.call(
"date.range.type",
"search_read",
[]
);
});
},
async onPropsUpdated(p) {
await super.onPropsUpdated.apply(this, arguments);
let domain = null;
let isSupported = true;
try {
domain = new Domain(p.domain);
} catch {
isSupported = false;
}
if (!isSupported) {
this.tree = null;
this.defaultCondition = null;
this.fieldDefs = {};
this.showArchivedCheckbox = false;
this.includeArchived = false;
return;
}
const tree = treeFromDomain(domain);
const getFieldDef = await this.makeGetFieldDef(p.resModel, tree, ["active"]);
this.tree = treeFromDomainDateRange(domain, {
getFieldDef: getFieldDef,
distributeNot: !p.isDebugMode,
});
},
getOperatorEditorInfo(fieldDef) {
const info = super.getOperatorEditorInfo(fieldDef);
const dateRanges = this.dateRanges;
const dateRangeTypes = this.dateRangeTypes.filter((dt) => dt.date_ranges_exist);
patch(info, {
extractProps({value: [operator]}) {
const props = super.extractProps.apply(this, arguments);
const isDateField =
fieldDef &&
(fieldDef.type === "date" || fieldDef.type === "datetime");
const hasDateRanges = isDateField && dateRanges.length;
const hasDateRangeTypes = isDateField && dateRangeTypes.length;
if (hasDateRanges) {
if (operator.includes("daterange")) {
props.options.pop();
}
if (operator === "daterange") {
props.value = "daterange";
}
props.options.push(["daterange", "daterange"]);
}
if (hasDateRangeTypes) {
const selectedDateRange = dateRangeTypes.find(
(rangeType) =>
rangeType.id === Number(operator.split("daterange_")[1])
);
if (selectedDateRange) {
props.value = operator;
}
props.options.push(
...dateRangeTypes.map((rangeType) => [
`daterange_${rangeType.id}`,
`in ${rangeType.name}`,
])
);
}
return props;
},
});
return info;
},
update(tree) {
const archiveDomain = this.includeArchived ? ARCHIVED_DOMAIN : `[]`;
const domain = tree
? Domain.and([domainFromTreeDateRange(tree), archiveDomain]).toString()
: archiveDomain;
this.props.update(domain);
},
});

View File

@@ -0,0 +1,140 @@
import {
deserializeDate,
deserializeDateTime,
serializeDate,
serializeDateTime,
} from "@web/core/l10n/dates";
import {Select} from "@web/core/tree_editor/tree_editor_components";
import {TreeEditor} from "@web/core/tree_editor/tree_editor";
import {patch} from "@web/core/utils/patch";
function toDateTime(date, type, end) {
if (type === "date") {
return date;
}
let jsDate = deserializeDate(date);
if (end) {
jsDate = luxon.DateTime.fromObject({
...jsDate.c,
hour: 23,
minute: 59,
second: 59,
});
}
return serializeDateTime(jsDate);
}
function fromDateTime(date, type) {
if (type === "date") {
return date;
}
return serializeDate(deserializeDateTime(date));
}
patch(TreeEditor.prototype, {
setup() {
super.setup();
},
getValueEditorInfo(node) {
const fieldDef = this.getFieldDef(node.path);
const info = super.getValueEditorInfo.apply(this, arguments);
if (
fieldDef &&
(fieldDef.type === "date" || fieldDef.type === "datetime") &&
node.operator.includes("daterange")
) {
info.component = Select;
}
if (typeof this.env.domain !== "undefined") {
let dateRanges = this.env.domain.dateRanges;
if (this.update_operator && this.update_operator.split("daterange_")[1]) {
dateRanges = this.env.domain.dateRanges.filter(
(range) =>
range.type_id[0] ===
Number(this.update_operator.split("daterange_")[1])
);
}
patch(info, {
extractProps({value, update}) {
const props = super.extractProps.apply(this, arguments);
if (
fieldDef &&
(fieldDef.type === "date" || fieldDef.type === "datetime") &&
node.operator.includes("daterange")
) {
let selected = dateRanges.find(
(range) =>
range.date_start ===
fromDateTime(value[1], fieldDef.type) &&
range.date_end === fromDateTime(value[0], fieldDef.type)
);
if (!selected) {
selected = dateRanges[0];
update([
toDateTime(selected.date_end, fieldDef.type),
toDateTime(selected.date_start, fieldDef.type, true),
]);
}
return {
options: dateRanges.map((dt) => [dt.id, dt.name]),
update: (v) => {
const range = dateRanges.find((r) => r.id === v);
update([
toDateTime(range.date_end, fieldDef.type),
toDateTime(range.date_start, fieldDef.type, true),
]);
},
value: selected.id,
};
}
return props;
},
isSupported(value) {
if (node.operator.includes("daterange")) {
return Array.isArray(value) && value.length === 2;
}
return super.isSupported.apply(this, arguments);
},
});
}
return info;
},
getOperatorEditorInfo(node) {
const info = super.getOperatorEditorInfo(node);
patch(info, {
isSupported([operator]) {
if (node.operator.includes("daterange")) {
return (
typeof operator === "string" && operator.includes("daterange")
);
}
return super.isSupported.apply(this, arguments);
},
});
return info;
},
updateLeafOperator(node, operator) {
super.updateLeafOperator.apply(this, arguments);
this.update_operator = operator;
const fieldDef = this.getFieldDef(node.path);
if (typeof this.env.domain !== "undefined") {
let dateRanges = this.env.domain.dateRanges.filter(
(range) => range.type_id[0] === Number(operator.split("daterange_")[1])
);
if (!dateRanges.length) {
dateRanges = this.env.domain.dateRanges;
}
if (operator.includes("daterange") && dateRanges) {
node.value = [
toDateTime(dateRanges[0].date_end, fieldDef.type),
toDateTime(dateRanges[0].date_start, fieldDef.type, true),
];
this.notifyChanges();
}
}
},
});