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.

123 lines
3.8 KiB

  1. # Copyright 2020 Creu Blanca
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  3. from odoo import api, fields, models
  4. import ast
  5. from odoo.tools.safe_eval import safe_eval
  6. class KpiKpi(models.Model):
  7. _name = "kpi.kpi"
  8. _description = "Kpi Kpi"
  9. name = fields.Char(required=True)
  10. active = fields.Boolean(default=True)
  11. cron_id = fields.Many2one("ir.cron", readonly=True, copy=False)
  12. computation_method = fields.Selection(
  13. [("function", "Function"), ("code", "Code")], required=True
  14. )
  15. value = fields.Serialized()
  16. dashboard_item_ids = fields.One2many("kpi.dashboard.item", inverse_name="kpi_id")
  17. model_id = fields.Many2one("ir.model",)
  18. function = fields.Char()
  19. args = fields.Char()
  20. kwargs = fields.Char()
  21. widget = fields.Selection(
  22. [("number", "Number"), ("meter", "Meter"), ("graph", "Graph")],
  23. required=True,
  24. default="number",
  25. )
  26. value_last_update = fields.Datetime(readonly=True)
  27. prefix = fields.Char()
  28. suffix = fields.Char()
  29. action_ids = fields.One2many(
  30. "kpi.kpi.action",
  31. inverse_name='kpi_id',
  32. help="Actions that can be opened from the KPI"
  33. )
  34. code = fields.Text("Code")
  35. def _cron_vals(self):
  36. return {
  37. "name": self.name,
  38. "model_id": self.env.ref("kpi_dashboard.model_kpi_kpi").id,
  39. "interval_number": 1,
  40. "interval_type": "hours",
  41. "state": "code",
  42. "code": "model.browse(%s).compute()" % self.id,
  43. "active": True,
  44. }
  45. def compute(self):
  46. for record in self:
  47. record._compute()
  48. return True
  49. def _compute(self):
  50. self.write(
  51. {
  52. "value": getattr(
  53. self, "_compute_value_%s" % self.computation_method
  54. )()
  55. }
  56. )
  57. notifications = []
  58. for dashboard_item in self.dashboard_item_ids:
  59. channel = "kpi_dashboard_%s" % dashboard_item.dashboard_id.id
  60. notifications.append([channel, dashboard_item._read_dashboard()])
  61. if notifications:
  62. self.env["bus.bus"].sendmany(notifications)
  63. def _compute_value_function(self):
  64. obj = self
  65. if self.model_id:
  66. obj = self.env[self.model_id.model]
  67. args = ast.literal_eval(self.args or "[]")
  68. kwargs = ast.literal_eval(self.kwargs or "{}")
  69. return getattr(obj, self.function)(*args, **kwargs)
  70. def generate_cron(self):
  71. self.ensure_one()
  72. self.cron_id = self.env["ir.cron"].create(self._cron_vals())
  73. @api.multi
  74. def write(self, vals):
  75. if "value" in vals:
  76. vals["value_last_update"] = fields.Datetime.now()
  77. return super().write(vals)
  78. def _get_code_input_dict(self):
  79. return {
  80. "self": self,
  81. "model": self,
  82. }
  83. def _compute_value_code(self):
  84. results = self._get_code_input_dict()
  85. safe_eval(self.code or "", results, mode="exec", nocopy=True)
  86. return results.get("result", {})
  87. class KpiKpiAction(models.Model):
  88. _name = 'kpi.kpi.action'
  89. _description = 'KPI action'
  90. kpi_id = fields.Many2one('kpi.kpi', required=True, ondelete='cascade')
  91. action = fields.Reference(
  92. selection=[('ir.actions.report', 'ir.actions.report'),
  93. ('ir.actions.act_window', 'ir.actions.act_window'),
  94. ('ir.actions.act_url', 'ir.actions.act_url'),
  95. ('ir.actions.server', 'ir.actions.server'),
  96. ('ir.actions.client', 'ir.actions.client')],
  97. required=True,
  98. )
  99. def read_dashboard(self):
  100. result = []
  101. for r in self:
  102. result.append({
  103. 'id': r.action.id,
  104. 'type': r.action._name,
  105. 'name': r.action.name
  106. })
  107. return result