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 @@
-
+
+
+
+