OCA reporting engine fork for dev and update.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
5.6 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2012 - Now Savoir-faire Linux <https://www.savoirfairelinux.com/>
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. from openerp import fields, models, api
  5. from openerp.tools.safe_eval import safe_eval
  6. import re
  7. def is_one_value(result):
  8. # check if sql query returns only one value
  9. if type(result) is dict and 'value' in result.dictfetchone():
  10. return True
  11. elif type(result) is list and 'value' in result[0]:
  12. return True
  13. else:
  14. return False
  15. RE_SELECT_QUERY = re.compile('.*(' + '|'.join((
  16. 'INSERT',
  17. 'UPDATE',
  18. 'DELETE',
  19. 'CREATE',
  20. 'ALTER',
  21. 'DROP',
  22. 'GRANT',
  23. 'REVOKE',
  24. 'INDEX',
  25. )) + ')')
  26. def is_sql_or_ddl_statement(query):
  27. """Check if sql query is a SELECT statement"""
  28. return not RE_SELECT_QUERY.match(query.upper())
  29. class KPIThresholdRange(models.Model):
  30. """
  31. KPI Threshold Range
  32. """
  33. _name = "kpi.threshold.range"
  34. _description = "KPI Threshold Range"
  35. name = fields.Char('Name', size=50, required=True)
  36. valid = fields.Boolean(string='Valid', required=True,
  37. compute="_compute_is_valid_range", default=True)
  38. invalid_message = fields.Char(string='Message', size=100,
  39. compute="_compute_is_valid_range")
  40. min_type = fields.Selection((
  41. ('static', 'Fixed value'),
  42. ('python', 'Python Code'),
  43. ('local', 'SQL - Local DB'),
  44. ('external', 'SQL - Externa DB'),
  45. ), 'Min Type', required=True)
  46. min_value = fields.Float(string='Minimum', compute="_compute_min_value")
  47. min_fixed_value = fields.Float('Minimum')
  48. min_code = fields.Text('Minimum Computation Code')
  49. min_error = fields.Char('Error', compute="_compute_min_value")
  50. min_dbsource_id = fields.Many2one(
  51. 'base.external.dbsource',
  52. 'External DB Source',
  53. )
  54. max_type = fields.Selection((
  55. ('static', 'Fixed value'),
  56. ('python', 'Python Code'),
  57. ('local', 'SQL - Local DB'),
  58. ('external', 'SQL - External DB'),
  59. ), 'Max Type', required=True)
  60. max_value = fields.Float(string='Maximum', compute="_compute_max_value")
  61. max_fixed_value = fields.Float('Maximum')
  62. max_code = fields.Text('Maximum Computation Code')
  63. max_error = fields.Char('Error', compute="_compute_max_value")
  64. max_dbsource_id = fields.Many2one(
  65. 'base.external.dbsource',
  66. 'External DB Source',
  67. )
  68. color = fields.Char(
  69. string="Color",
  70. help="Choose your color"
  71. )
  72. threshold_ids = fields.Many2many(
  73. 'kpi.threshold',
  74. 'kpi_threshold_range_rel',
  75. 'range_id',
  76. 'threshold_id',
  77. 'Thresholds',
  78. )
  79. company_id = fields.Many2one(
  80. 'res.company', 'Company',
  81. default=lambda self: self.env.user.company_id.id)
  82. @api.multi
  83. def _compute_min_value(self):
  84. for obj in self:
  85. value = None
  86. error = None
  87. try:
  88. if obj.min_type == 'local' and is_sql_or_ddl_statement(
  89. obj.min_code):
  90. self.env.cr.execute(obj.min_code)
  91. dic = self.env.cr.dictfetchall()
  92. if is_one_value(dic):
  93. value = dic[0]['value']
  94. elif (obj.min_type == 'external' and obj.min_dbsource_id.id and
  95. is_sql_or_ddl_statement(obj.min_code)):
  96. dbsrc_obj = obj.min_dbsource_id
  97. res = dbsrc_obj.execute(obj.min_code)
  98. if is_one_value(res):
  99. value = res[0]['value']
  100. elif obj.min_type == 'python':
  101. value = safe_eval(obj.min_code)
  102. else:
  103. value = obj.min_fixed_value
  104. except Exception as e:
  105. value = None
  106. error = str(e)
  107. obj.min_value = value
  108. obj.min_error = error
  109. @api.multi
  110. def _compute_max_value(self):
  111. for obj in self:
  112. value = None
  113. error = None
  114. try:
  115. if obj.max_type == 'local' and is_sql_or_ddl_statement(
  116. obj.max_code):
  117. self.env.cr.execute(obj.max_code)
  118. dic = self.env.cr.dictfetchall()
  119. if is_one_value(dic):
  120. value = dic[0]['value']
  121. elif (obj.max_type == 'external' and obj.max_dbsource_id.id and
  122. is_sql_or_ddl_statement(obj.max_code)):
  123. dbsrc_obj = obj.max_dbsource_id
  124. res = dbsrc_obj.execute(obj.max_code)
  125. if is_one_value(res):
  126. value = res[0]['value']
  127. elif obj.max_type == 'python':
  128. value = safe_eval(obj.max_code)
  129. else:
  130. value = obj.max_fixed_value
  131. except Exception as e:
  132. value = None
  133. error = str(e)
  134. obj.max_value = value
  135. obj.max_error = error
  136. @api.multi
  137. def _compute_is_valid_range(self):
  138. for obj in self:
  139. if obj.min_error or obj.max_error:
  140. obj.valid = False
  141. obj.invalid_message = (
  142. "Either minimum or maximum value has "
  143. "computation errors. Please fix them.")
  144. elif obj.max_value < obj.min_value:
  145. obj.valid = False
  146. obj.invalid_message = (
  147. "Minimum value is greater than the maximum "
  148. "value! Please adjust them.")
  149. else:
  150. obj.valid = True
  151. obj.invalid_message = ""