From 1529a7bf93e3282dded8e4a2210a25d76ef380cf Mon Sep 17 00:00:00 2001 From: Carlos Roca Date: Mon, 27 Nov 2023 11:09:47 +0100 Subject: [PATCH] [IMP] web_pivot_computed_measure: Function that eval operations --- web_pivot_computed_measure/README.rst | 2 +- web_pivot_computed_measure/__manifest__.py | 2 +- .../static/description/index.html | 2 +- .../static/src/helpers/utils.esm.js | 131 +++++++++++++++--- 4 files changed, 117 insertions(+), 20 deletions(-) diff --git a/web_pivot_computed_measure/README.rst b/web_pivot_computed_measure/README.rst index 7b53c329a..c5dc6f1ac 100644 --- a/web_pivot_computed_measure/README.rst +++ b/web_pivot_computed_measure/README.rst @@ -7,7 +7,7 @@ Web Pivot Computed Measure !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:ece4336d91177883eff784573de23cd6a67b1044e080eb758f7de5e6374d57f0 + !! source digest: sha256:34691d378ce32fade67311831059070fab3df66f5cb2ec7fa88287018b85de7b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/web_pivot_computed_measure/__manifest__.py b/web_pivot_computed_measure/__manifest__.py index 7f172c2ed..e77ae591a 100644 --- a/web_pivot_computed_measure/__manifest__.py +++ b/web_pivot_computed_measure/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Web Pivot Computed Measure", "category": "web", - "version": "15.0.1.0.2", + "version": "15.0.1.0.3", "author": "Tecnativa, Odoo Community Association (OCA)", "license": "AGPL-3", "website": "https://github.com/OCA/web", diff --git a/web_pivot_computed_measure/static/description/index.html b/web_pivot_computed_measure/static/description/index.html index b124f1866..f3e6801f0 100644 --- a/web_pivot_computed_measure/static/description/index.html +++ b/web_pivot_computed_measure/static/description/index.html @@ -367,7 +367,7 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:ece4336d91177883eff784573de23cd6a67b1044e080eb758f7de5e6374d57f0 +!! source digest: sha256:34691d378ce32fade67311831059070fab3df66f5cb2ec7fa88287018b85de7b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runboat

Adds support for computed measures on the pivot view.

diff --git a/web_pivot_computed_measure/static/src/helpers/utils.esm.js b/web_pivot_computed_measure/static/src/helpers/utils.esm.js index c50480220..df95c84bc 100644 --- a/web_pivot_computed_measure/static/src/helpers/utils.esm.js +++ b/web_pivot_computed_measure/static/src/helpers/utils.esm.js @@ -1,27 +1,124 @@ /** @odoo-module **/ -/* Copyright 2022 Tecnativa - Carlos Roca +/* Copyright 2023 Tecnativa - Carlos Roca * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */ /** - * Helper function to eval text for a given object + * Function that traverse the text given character by character * * @param {String} text - * @param {Object} vals - * @returns {any} + * @returns {Array} */ -export const evalOperation = (text, vals) => { - for (const variable in vals) { - if (vals.hasOwnProperty(variable)) { - const regex = new RegExp(variable, "g"); - text = text.replace(regex, vals[variable]); +function getTokensFromText(text) { + const symbols = ["+", "-", "*", "/", "(", ")"]; + const tokens = []; + let token = ""; + for (let i = 0; i < text.length; i++) { + const c = text[i]; + if (c === " ") continue; + if (symbols.includes(c)) { + if (token !== "") { + tokens.push(token); + token = ""; + } + tokens.push(c); + } else { + token += c; } } - try { - // eslint-disable-next-line no-eval - const res = eval(text); - return res; - } catch (error) { - console.error("Error trying to eval operation:", error); - return; + if (token !== "") { + tokens.push(token); } -}; + return tokens; +} + +/** + * Function that executes an operation between the last two operands in the operands stack + * and the last operator in the operators stack, and saves the result in the operands stack. + * + * @param {Array} operands + * @param {Array} operators + */ +function executeOperation(operands, operators) { + const b = operands.pop(); + const a = operands.pop(); + const op = operators.pop(); + switch (op) { + case "+": + operands.push(a + b); + break; + case "-": + operands.push(a - b); + break; + case "*": + operands.push(a * b); + break; + case "/": + operands.push(a / b); + break; + } +} + +/** + * Function that returns the precedence of an operator + * + * @param {String} op + * @returns {Number} + */ +function precedence(op) { + if (op === "+" || op === "-") { + return 1; + } + if (op === "*" || op === "/") { + return 2; + } + if (op === "(" || op === ")") { + return 0; + } +} + +/** + * Helper function that takes a mathematical expression in text form and an object + * of variable values, evaluates the expression, and returns the result. + * + * @param {String} text + * @param {Object} values + * @returns {any} + */ +export function evalOperation(text, values) { + const tokens = getTokensFromText(text); + const operands = []; + const operators = []; + for (const token of tokens) { + if (!isNaN(token)) { + // If the token is a number, convert it to a number and add it to the operands stack + operands.push(Number(token)); + } else if (token in values) { + // If the token is a variable, get its value from the object and add it to the operands stack + operands.push(values[token]); + } else if (token === "(") { + // If the token is an open parenthesis, add it to the operators stack + operators.push(token); + } else if (token === ")") { + // If the token is a closing parenthesis, pop and execute operators from the stack until an open parenthesis is found + while (operators.length > 0 && operators[operators.length - 1] !== "(") { + executeOperation(operands, operators); + } + // Pop the open parenthesis from the operators stack + operators.pop(); + } else { + // If the token is an operator, pop and execute operators from the stack while they have equal or higher precedence than the token + while ( + operators.length > 0 && + precedence(operators[operators.length - 1]) >= precedence(token) + ) { + executeOperation(operands, operators); + } + // Add the token to the operators stack + operators.push(token); + } + } + while (operators.length > 0) { + executeOperation(operands, operators); + } + return operands.pop(); +}