mirror of https://github.com/OCA/web.git
commit
14828a257e
|
@ -0,0 +1,124 @@
|
|||
/** @odoo-module **/
|
||||
/* Copyright 2023 Tecnativa - Carlos Roca
|
||||
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */
|
||||
|
||||
/**
|
||||
* Function that traverse the text given character by character
|
||||
*
|
||||
* @param {String} text
|
||||
* @returns {Array}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
import {PivotModel} from "@web/views/pivot/pivot_model";
|
||||
import {patch} from "web.utils";
|
||||
import {computeReportMeasures} from "@web/views/helpers/utils";
|
||||
import {evalOperation} from "../helpers/utils.esm";
|
||||
|
||||
patch(PivotModel.prototype, "web_pivot_computed_measure.PivotModel", {
|
||||
/**
|
||||
|
@ -148,7 +149,7 @@ patch(PivotModel.prototype, "web_pivot_computed_measure.PivotModel", {
|
|||
subGroupData[cm.id] = false;
|
||||
} else {
|
||||
// eslint-disable-next-line no-undef
|
||||
subGroupData[cm.id] = py.eval(cm.operation, subGroupData);
|
||||
subGroupData[cm.id] = evalOperation(cm.operation, subGroupData);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue