diff --git a/kpi/__manifest__.py b/kpi/__manifest__.py
index 81a69b68ef..15104625a8 100644
--- a/kpi/__manifest__.py
+++ b/kpi/__manifest__.py
@@ -14,8 +14,6 @@
"security/ir.model.access.csv",
"views/kpi_category_views.xml",
"views/kpi_history_views.xml",
- "views/kpi_threshold_range_views.xml",
- "views/kpi_threshold_views.xml",
"views/kpi_views.xml",
"views/menu.xml",
"data/kpi_data.xml",
@@ -23,8 +21,6 @@
"images": [
"images/kpi_definition.png",
"images/kpi_computation.png",
- "images/kpi_threshold.png",
- "images/kpi_range.png",
],
"installable": True,
}
diff --git a/kpi/models/__init__.py b/kpi/models/__init__.py
index ae1cb46571..0244fa0d6d 100644
--- a/kpi/models/__init__.py
+++ b/kpi/models/__init__.py
@@ -1,7 +1,5 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import kpi_category
-from . import kpi_threshold_range
-from . import kpi_threshold
from . import kpi_history
from . import kpi
diff --git a/kpi/models/kpi.py b/kpi/models/kpi.py
index 169499befc..ebc2b1c223 100644
--- a/kpi/models/kpi.py
+++ b/kpi/models/kpi.py
@@ -57,7 +57,6 @@ class KPI(models.Model):
name = fields.Char(required=True)
description = fields.Text()
category_id = fields.Many2one("kpi.category", required=True)
- threshold_id = fields.Many2one("kpi.threshold", required=True)
periodicity = fields.Integer(default=1)
periodicity_uom = fields.Selection(
@@ -85,7 +84,6 @@ class KPI(models.Model):
"KPI Computation Type",
)
- dbsource_id = fields.Many2one("base.external.dbsource", "External DB Source")
kpi_code = fields.Text(
help=(
"SQL code must return the result as 'value' " "(i.e. 'SELECT 5 AS value')."
@@ -121,29 +119,18 @@ def _get_kpi_value(self):
self.ensure_one()
kpi_value = 0
if self.kpi_code:
- if self.kpi_type == "local" and is_sql_or_ddl_statement(self.kpi_code):
+ if self.kpi_type == "sql" and is_sql_or_ddl_statement(self.kpi_code):
self.env.cr.execute(self.kpi_code)
dic = self.env.cr.dictfetchall()
if is_one_value(dic):
kpi_value = dic[0]["value"]
- elif (
- self.kpi_type == "external"
- and self.dbsource_id.id
- and is_sql_or_ddl_statement(self.kpi_code)
- ):
- dbsrc_obj = self.dbsource_id
- res = dbsrc_obj.execute(self.kpi_code)
- if is_one_value(res):
- kpi_value = res[0]["value"]
elif self.kpi_type == "python":
kpi_value = safe_eval(self.kpi_code, {"self": self})
if isinstance(kpi_value, dict):
res = kpi_value
else:
- threshold_obj = self.threshold_id
res = {
"value": kpi_value,
- "color": threshold_obj.get_color(kpi_value),
}
res.update({"kpi_id": self.id})
return res
diff --git a/kpi/models/kpi_threshold.py b/kpi/models/kpi_threshold.py
deleted file mode 100644
index 66f363bcc3..0000000000
--- a/kpi/models/kpi_threshold.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# Copyright 2012 - Now Savoir-faire Linux
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-from odoo import _, api, exceptions, fields, models
-
-
-class KPIThreshold(models.Model):
- """KPI Threshold."""
-
- _name = "kpi.threshold"
- _description = "KPI Threshold"
-
- def _compute_is_valid_threshold(self):
- for obj in self:
- # check if ranges overlap
- # TODO: This code can be done better
- obj.valid = True
- for range1 in obj.range_ids:
- if not range1.valid:
- obj.valid = False
- break
- for range2 in obj.range_ids - range1:
- if (
- range1.max_value >= range2.min_value
- and range1.min_value <= range2.max_value
- ):
- obj.valid = False
- break
- if obj.valid:
- obj.invalid_message = None
- else:
- obj.invalid_message = (
- "Some ranges are invalid or overlapping. "
- "Please make sure your ranges do not overlap."
- )
-
- name = fields.Char(required=True)
- range_ids = fields.Many2many(
- "kpi.threshold.range",
- "kpi_threshold_range_rel",
- "threshold_id",
- "range_id",
- "Ranges",
- )
- valid = fields.Boolean(
- required=True,
- compute="_compute_is_valid_threshold",
- default=True,
- )
- invalid_message = fields.Char(
- string="Message", size=100, compute="_compute_is_valid_threshold"
- )
- kpi_ids = fields.One2many("kpi", "threshold_id", "KPIs")
- company_id = fields.Many2one(
- "res.company", "Company", default=lambda self: self.env.company
- )
-
- @api.model
- def create(self, data):
- # check if ranges overlap
- # TODO: This code can be done better
- range_obj1 = self.env["kpi.threshold.range"]
- range_obj2 = self.env["kpi.threshold.range"]
- if data.get("range_ids"):
- for range1 in data["range_ids"][0][2]:
- range_obj1 = range_obj1.browse(range1)
- for range2 in data["range_ids"][0][2]:
- range_obj2 = range_obj2.browse(range2)
- if (
- range_obj1.valid
- and range_obj2.valid
- and range_obj1.min_value < range_obj2.min_value
- ):
- if range_obj1.max_value > range_obj2.min_value:
- raise exceptions.Warning(
- _("Two of your ranges are overlapping."),
- _("Make sure your ranges do not overlap!"),
- )
- range_obj2 = self.env["kpi.threshold.range"]
- range_obj1 = self.env["kpi.threshold.range"]
- return super(KPIThreshold, self).create(data)
-
- def get_color(self, kpi_value):
- color = "#FFFFFF"
- for obj in self:
- for range_obj in obj.range_ids:
- if (
- range_obj.min_value <= kpi_value <= range_obj.max_value
- and range_obj.valid
- ):
- color = range_obj.color
- return color
diff --git a/kpi/models/kpi_threshold_range.py b/kpi/models/kpi_threshold_range.py
deleted file mode 100644
index a5d4b217b8..0000000000
--- a/kpi/models/kpi_threshold_range.py
+++ /dev/null
@@ -1,174 +0,0 @@
-# Copyright 2012 - Now Savoir-faire Linux
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-import re
-
-from odoo import api, fields, models
-from odoo.tools.safe_eval import safe_eval
-
-
-def is_one_value(result):
- # check if sql query returns only one value
- if type(result) is dict and "value" in result.dictfetchone():
- return True
- elif type(result) is list and "value" in result[0]:
- return True
- else:
- return False
-
-
-RE_SELECT_QUERY = re.compile(
- ".*("
- + "|".join(
- (
- "INSERT",
- "UPDATE",
- "DELETE",
- "CREATE",
- "ALTER",
- "DROP",
- "GRANT",
- "REVOKE",
- "INDEX",
- )
- )
- + ")"
-)
-
-
-def is_sql_or_ddl_statement(query):
- """Check if sql query is a SELECT statement"""
- return not RE_SELECT_QUERY.match(query.upper())
-
-
-class KPIThresholdRange(models.Model):
- """
- KPI Threshold Range
- """
-
- _name = "kpi.threshold.range"
- _description = "KPI Threshold Range"
-
- @api.model
- def _selection_value_type(self):
- return [
- ("static", "Fixed value"),
- ("python", "Python Code"),
- ("local", "SQL - Local DB"),
- ("external", "SQL - External DB"),
- ]
-
- name = fields.Char(required=True)
- valid = fields.Boolean(
- required=True, compute="_compute_is_valid_range", default=True
- )
- invalid_message = fields.Char(
- string="Message", size=100, compute="_compute_is_valid_range"
- )
- min_type = fields.Selection(selection="_selection_value_type", required=True)
- min_value = fields.Float(string="Minimum Value", compute="_compute_min_value")
- min_fixed_value = fields.Float("Minimum Fixed Value")
- min_code = fields.Text("Minimum Computation Code")
- min_error = fields.Char("Minimum Error", compute="_compute_min_value")
- min_dbsource_id = fields.Many2one(
- "base.external.dbsource",
- "External DB Source Minimum",
- )
- max_type = fields.Selection(selection="_selection_value_type", required=True)
- max_value = fields.Float(string="Maximum Value", compute="_compute_max_value")
- max_fixed_value = fields.Float("Maximum Fixed Value")
- max_code = fields.Text("Maximum Computation Code")
- max_error = fields.Char("Maximum Error", compute="_compute_max_value")
- max_dbsource_id = fields.Many2one(
- "base.external.dbsource",
- "External DB Source Maximum",
- )
-
- color = fields.Char(help="Choose your color")
-
- threshold_ids = fields.Many2many(
- "kpi.threshold",
- "kpi_threshold_range_rel",
- "range_id",
- "threshold_id",
- "Thresholds",
- )
- company_id = fields.Many2one(
- "res.company", "Company", default=lambda self: self.env.company
- )
-
- def _compute_min_value(self):
- for obj in self:
- value = None
- error = None
- try:
- if obj.min_type == "local" and is_sql_or_ddl_statement(obj.min_code):
- self.env.cr.execute(obj.min_code)
- dic = self.env.cr.dictfetchall()
- if is_one_value(dic):
- value = dic[0]["value"]
- elif (
- obj.min_type == "external"
- and obj.min_dbsource_id.id
- and is_sql_or_ddl_statement(obj.min_code)
- ):
- dbsrc_obj = obj.min_dbsource_id
- res = dbsrc_obj.execute(obj.min_code)
- if is_one_value(res):
- value = res[0]["value"]
- elif obj.min_type == "python":
- value = safe_eval(obj.min_code)
- else:
- value = obj.min_fixed_value
- except Exception as e:
- value = None
- error = str(e)
- obj.min_value = value
- obj.min_error = error
-
- def _compute_max_value(self):
- for obj in self:
- value = None
- error = None
- try:
- if obj.max_type == "local" and is_sql_or_ddl_statement(obj.max_code):
- self.env.cr.execute(obj.max_code)
- dic = self.env.cr.dictfetchall()
- if is_one_value(dic):
- value = dic[0]["value"]
- elif (
- obj.max_type == "external"
- and obj.max_dbsource_id.id
- and is_sql_or_ddl_statement(obj.max_code)
- ):
- dbsrc_obj = obj.max_dbsource_id
- res = dbsrc_obj.execute(obj.max_code)
- if is_one_value(res):
- value = res[0]["value"]
- elif obj.max_type == "python":
- value = safe_eval(obj.max_code)
- else:
- value = obj.max_fixed_value
- except Exception as e:
- value = None
- error = str(e)
- obj.max_value = value
- obj.max_error = error
-
- def _compute_is_valid_range(self):
- for obj in self:
- if obj.min_error or obj.max_error:
- obj.valid = False
- obj.invalid_message = (
- "Either minimum or maximum value has "
- "computation errors. Please fix them."
- )
- elif obj.max_value < obj.min_value:
- obj.valid = False
- obj.invalid_message = (
- "Minimum value is greater than the maximum "
- "value! Please adjust them."
- )
- else:
- obj.valid = True
- obj.invalid_message = ""
diff --git a/kpi/security/ir.model.access.csv b/kpi/security/ir.model.access.csv
index 0d79d817d2..3c4eefef43 100644
--- a/kpi/security/ir.model.access.csv
+++ b/kpi/security/ir.model.access.csv
@@ -2,11 +2,6 @@
"access_kpi_user","kpi.user","model_kpi","base.group_user",1,0,0,0
"access_kpi_history_user","kpi.history.user","model_kpi_history","base.group_user",1,0,0,0
"access_kpi_category_user","kpi.category.user","model_kpi_category","base.group_user",1,0,0,0
-"access_kpi_threshold_user","kpi.threshold.user","model_kpi_threshold","base.group_user",1,0,0,0
-"access_kpi_threshold_range_user","kpi.threshold.range.user","model_kpi_threshold_range","base.group_user",1,0,0,0
"access_kpi_manager","kpi.manager","model_kpi","kpi.group_kpi_manager",1,1,1,1
"access_kpi_history_manager","kpi.history.user","model_kpi_history","kpi.group_kpi_manager",1,1,1,1
"access_kpi_category_manager","kpi.category.manager","model_kpi_category","kpi.group_kpi_manager",1,1,1,1
-"access_kpi_threshold_manager","kpi.threshold.manager","model_kpi_threshold","kpi.group_kpi_manager",1,1,1,1
-"access_kpi_threshold_range_manager","kpi.threshold.range.manager","model_kpi_threshold_range","kpi.group_kpi_manager",1,1,1,1
-"access_base_external_dbsource_manager","base.external.dbsource.manager","base_external_dbsource.model_base_external_dbsource","base.group_user",1,1,1,1
diff --git a/kpi/security/kpi_security.xml b/kpi/security/kpi_security.xml
index 82f32238b7..ded1ee0e34 100644
--- a/kpi/security/kpi_security.xml
+++ b/kpi/security/kpi_security.xml
@@ -19,22 +19,6 @@
name="domain_force"
>['|',('company_id','=',False),('company_id', 'in', company_ids)]
-
- kpi_threshold_range multi-company
-
-
- ['|',('company_id','=',False),('company_id', 'in', company_ids)]
-
-
- kpi_threshold multi-company
-
-
- ['|',('company_id','=',False),('company_id', 'in', company_ids)]
-
kpi_history multi-company
diff --git a/kpi/views/kpi_threshold_range_views.xml b/kpi/views/kpi_threshold_range_views.xml
deleted file mode 100644
index 2a323762a5..0000000000
--- a/kpi/views/kpi_threshold_range_views.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-
-
-
-
-
- kpi.threshold.range.tree
- kpi.threshold.range
-
-
-
-
-
-
-
-
-
-
-
-
- kpi.threshold.range.form
- kpi.threshold.range
-
-
-
-
-
- Ranges
- kpi.threshold.range
- tree,form
-
-
-
diff --git a/kpi/views/kpi_threshold_views.xml b/kpi/views/kpi_threshold_views.xml
deleted file mode 100644
index 46eabc11d5..0000000000
--- a/kpi/views/kpi_threshold_views.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
- kpi.threshold.tree
- kpi.threshold
-
-
-
-
-
-
-
-
-
- kpi.threshold.form
- kpi.threshold
-
-
-
-
-
- Thresholds
- kpi.threshold
- tree,form
-
-
-
diff --git a/kpi/views/kpi_views.xml b/kpi/views/kpi_views.xml
index 6be42b6f9c..f5856bd99e 100644
--- a/kpi/views/kpi_views.xml
+++ b/kpi/views/kpi_views.xml
@@ -91,7 +91,6 @@
-
@@ -122,11 +121,6 @@
-
@@ -142,7 +136,7 @@
KPI Dashboard
kpi
- kanban,form
+ graph,pivot,kanban,form
@@ -154,7 +148,7 @@
KPI Maintenance
kpi
- tree,form
+ kanban,tree,form
diff --git a/kpi/views/menu.xml b/kpi/views/menu.xml
index b951090e83..654ebdb9ac 100644
--- a/kpi/views/menu.xml
+++ b/kpi/views/menu.xml
@@ -32,25 +32,4 @@
parent="menu_configuration_kpi"
sequence="20"
/>
-
-
-