diff --git a/kpi_dashboard/models/kpi_kpi.py b/kpi_dashboard/models/kpi_kpi.py index 41e6c5b60..b6c7c030a 100644 --- a/kpi_dashboard/models/kpi_kpi.py +++ b/kpi_dashboard/models/kpi_kpi.py @@ -3,6 +3,7 @@ from odoo import api, fields, models import ast +from odoo.tools.safe_eval import safe_eval class KpiKpi(models.Model): @@ -13,7 +14,7 @@ class KpiKpi(models.Model): active = fields.Boolean(default=True) cron_id = fields.Many2one("ir.cron", readonly=True, copy=False) computation_method = fields.Selection( - [("function", "Function")], required=True + [("function", "Function"), ("code", "Code")], required=True ) value = fields.Serialized() dashboard_item_ids = fields.One2many("kpi.dashboard.item", inverse_name="kpi_id") @@ -34,6 +35,7 @@ class KpiKpi(models.Model): inverse_name='kpi_id', help="Actions that can be opened from the KPI" ) + code = fields.Text("Code") def _cron_vals(self): return { @@ -84,6 +86,17 @@ class KpiKpi(models.Model): vals["value_last_update"] = fields.Datetime.now() return super().write(vals) + def _get_code_input_dict(self): + return { + "self": self, + "model": self, + } + + def _compute_value_code(self): + results = self._get_code_input_dict() + safe_eval(self.code or "", results, mode="exec", nocopy=True) + return results.get("result", {}) + class KpiKpiAction(models.Model): _name = 'kpi.kpi.action' diff --git a/kpi_dashboard/readme/CONFIGURE.rst b/kpi_dashboard/readme/CONFIGURE.rst index c4d0bea03..bbbeb64de 100644 --- a/kpi_dashboard/readme/CONFIGURE.rst +++ b/kpi_dashboard/readme/CONFIGURE.rst @@ -8,6 +8,9 @@ Configure KPIs #. Meter: result must contain `value`, `min` and `max` #. Graph: result must contain a list on `graphs` containing `values`, `title` and `key` +#. In order to compute the KPI you can use a predefined function from a model or + use the code to directly compute it. + Configure dashboards ~~~~~~~~~~~~~~~~~~~~ diff --git a/kpi_dashboard/tests/__init__.py b/kpi_dashboard/tests/__init__.py new file mode 100644 index 000000000..c1545cc38 --- /dev/null +++ b/kpi_dashboard/tests/__init__.py @@ -0,0 +1 @@ +from . import test_formula diff --git a/kpi_dashboard/tests/test_formula.py b/kpi_dashboard/tests/test_formula.py new file mode 100644 index 000000000..4f37d9990 --- /dev/null +++ b/kpi_dashboard/tests/test_formula.py @@ -0,0 +1,31 @@ +# Copyright 2020 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestFormula(TransactionCase): + def test_computation(self): + kpi = self.env["kpi.kpi"].create( + { + "name": "DEMO KPI", + "widget": "number", + "computation_method": "code", + } + ) + self.assertFalse(kpi.value) + kpi.compute() + self.assertEqual(kpi.value, {}) + kpi.code = """ +result = {} +result['value'] = len(model.search([('id', '=', %s)])) +result['previous'] = len(model.search([('id', '!=', %s)])) + """ % ( + kpi.id, + kpi.id, + ) + kpi.compute() + value = kpi.value + self.assertTrue(value.get("value")) + self.assertEqual(value.get("value"), 1) + self.assertEqual(value.get("previous"), kpi.search_count([]) - 1) diff --git a/kpi_dashboard/views/kpi_kpi.xml b/kpi_dashboard/views/kpi_kpi.xml index 924d97068..72fc0d3c3 100644 --- a/kpi_dashboard/views/kpi_kpi.xml +++ b/kpi_dashboard/views/kpi_kpi.xml @@ -44,7 +44,12 @@ - + + + +