diff --git a/kpi/models/kpi.py b/kpi/models/kpi.py index 7fb5e33f15..0d22d4b697 100644 --- a/kpi/models/kpi.py +++ b/kpi/models/kpi.py @@ -4,12 +4,13 @@ import logging import re from datetime import datetime +from statistics import mean from dateutil.relativedelta import relativedelta from odoo import api, fields, models from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT -from odoo.tools.safe_eval import safe_eval +from odoo.tools.safe_eval import dateutil, safe_eval _logger = logging.getLogger(__name__) @@ -164,7 +165,13 @@ def _get_kpi_value(self): kpi_value = res[0]["value"] elif self.kpi_type == "python": kpi_value = safe_eval( - self.kpi_code, {"self": self, "datetime": fields.datetime} + self.kpi_code, + { + "self": self, + "datetime": fields.datetime, + "dateutil": dateutil, + "mean": mean, + }, ) if isinstance(kpi_value, dict): res = kpi_value diff --git a/kpi/tests/test_kpi.py b/kpi/tests/test_kpi.py index 4953efe3b2..e6aefd9de9 100644 --- a/kpi/tests/test_kpi.py +++ b/kpi/tests/test_kpi.py @@ -127,3 +127,47 @@ def test_kpi_python(self): self.assertEqual(len(kpi_history), 1) self.assertEqual(kpi_history.color, "#00FF00") self.assertEqual(kpi_history.value, 1.0) + + def test_kpi_python_dateutil(self): + kpi_category = self.env["kpi.category"].create({"name": "Dynamic KPIs"}) + kpi_threshold = self.env["kpi.threshold"].create( + {"name": "KPI Threshold for dynamic KPIs"} + ) + kpi = self.env["kpi"].create( + { + "name": "KPI with dateutil", + "description": "KPI using dateutil in python code", + "category_id": kpi_category.id, + "threshold_id": kpi_threshold.id, + "periodicity": 1, + "periodicity_uom": "day", + "kpi_type": "python", + "kpi_code": "dateutil.relativedelta.relativedelta(days=1).days", + } + ) + kpi.update_kpi_value() + kpi_history = self.env["kpi.history"].search([("kpi_id", "=", kpi.id)]) + self.assertEqual(len(kpi_history), 1) + self.assertEqual(kpi_history.value, 1.0) + + def test_kpi_python_mean(self): + kpi_category = self.env["kpi.category"].create({"name": "Dynamic KPIs"}) + kpi_threshold = self.env["kpi.threshold"].create( + {"name": "KPI Threshold for dynamic KPIs"} + ) + kpi = self.env["kpi"].create( + { + "name": "KPI with mean", + "description": "KPI using mean in python code", + "category_id": kpi_category.id, + "threshold_id": kpi_threshold.id, + "periodicity": 1, + "periodicity_uom": "day", + "kpi_type": "python", + "kpi_code": "mean([1.0, 2.0, 3.0])", + } + ) + kpi.update_kpi_value() + kpi_history = self.env["kpi.history"].search([("kpi_id", "=", kpi.id)]) + self.assertEqual(len(kpi_history), 1) + self.assertEqual(kpi_history.value, 2.0)