Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
96
date_range/static/src/js/condition_tree.esm.js
Normal file
96
date_range/static/src/js/condition_tree.esm.js
Normal 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));
|
||||
}
|
||||
107
date_range/static/src/js/domain_selector.esm.js
Normal file
107
date_range/static/src/js/domain_selector.esm.js
Normal 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);
|
||||
},
|
||||
});
|
||||
140
date_range/static/src/js/tree_editor.esm.js
Normal file
140
date_range/static/src/js/tree_editor.esm.js
Normal 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();
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user