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

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();
}
}
},
});