mirror of
https://gitlab.com/flectra-community/reporting-engine.git
synced 2024-12-23 12:51:47 +00:00
175 lines
5.7 KiB
Python
175 lines
5.7 KiB
Python
# Copyright 2012 - Now Savoir-faire Linux <https://www.savoirfairelinux.com/>
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
|
|
|
import re
|
|
|
|
from flectra import api, fields, models
|
|
from flectra.tools.safe_eval import safe_eval
|
|
|
|
|
|
def is_one_value(result):
|
|
# check if sql query returns only one value
|
|
if isinstance(result, dict) and "value" in result.dictfetchone():
|
|
return True
|
|
elif isinstance(result, 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 = ""
|