Browse Source

[IMP] kpi_dashboard: Set history & Add compute on the fly & Show value on kpi computation

12.0
Enric Tobella 4 years ago
parent
commit
793f128628
No known key found for this signature in database GPG Key ID: D76663C0B4023597
  1. 12
      kpi_dashboard/models/kpi_dashboard.py
  2. 102
      kpi_dashboard/models/kpi_kpi.py
  3. 2
      kpi_dashboard/security/ir.model.access.csv
  4. 68
      kpi_dashboard/static/src/js/field_widget.js
  5. 22
      kpi_dashboard/tests/test_formula.py
  6. 83
      kpi_dashboard/views/kpi_kpi.xml
  7. 1
      kpi_dashboard/views/webclient_templates.xml

12
kpi_dashboard/models/kpi_dashboard.py

@ -167,10 +167,18 @@ class KpiDashboardItem(models.Model):
"kpi_id": self.kpi_id.id,
"suffix": self.kpi_id.suffix or "",
"prefix": self.kpi_id.prefix or "",
"value": self.kpi_id.value,
"value_last_update": self.kpi_id.value_last_update,
}
)
if self.kpi_id.compute_on_fly:
vals.update({
"value": self.kpi_id._compute_value(),
"value_last_update": fields.Datetime.now(),
})
else:
vals.update({
"value": self.kpi_id.value,
"value_last_update": self.kpi_id.value_last_update,
})
if self.kpi_id.action_ids:
vals["actions"] = self.kpi_id.action_ids.read_dashboard()
else:

102
kpi_dashboard/models/kpi_kpi.py

@ -5,7 +5,9 @@ from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
import ast
from odoo.tools.safe_eval import safe_eval
from odoo.addons.base.models.ir_cron import _intervalTypes
import re
import json
class KpiKpi(models.Model):
@ -38,6 +40,26 @@ class KpiKpi(models.Model):
help="Actions that can be opened from the KPI"
)
code = fields.Text("Code")
store_history = fields.Boolean()
store_history_interval = fields.Selection(
selection=lambda self:
self.env['ir.cron']._fields['interval_type'].selection,
)
store_history_interval_number = fields.Integer()
compute_on_fly = fields.Boolean()
history_ids = fields.One2many("kpi.kpi.history", inverse_name="kpi_id")
computed_value = fields.Serialized(compute='_compute_computed_value')
computed_date = fields.Datetime(compute='_compute_computed_value')
@api.depends('value', 'value_last_update', 'compute_on_fly')
def _compute_computed_value(self):
for record in self:
if record.compute_on_fly:
record.computed_value = record._compute_value()
record.computed_date = fields.Datetime.now()
else:
record.computed_value = record.value
record.computed_date = record.value_last_update
def _cron_vals(self):
return {
@ -55,14 +77,32 @@ class KpiKpi(models.Model):
record._compute()
return True
def _generate_history_vals(self, value):
return {
"kpi_id": self.id,
"value": value,
"widget": self.widget,
}
def _compute_value(self):
return getattr(self, "_compute_value_%s" % self.computation_method)()
def _compute(self):
self.write(
{
"value": getattr(
self, "_compute_value_%s" % self.computation_method
)()
}
)
value = self._compute_value()
self.write({"value": value})
if self.store_history:
last = self.env['kpi.kpi.history'].search([
('kpi_id', '=', self.id)
], limit=1)
if (
not last or
not self.store_history_interval or
last.create_date + _intervalTypes[self.store_history_interval](
self.store_history_interval_number) < fields.Datetime.now()
):
self.env["kpi.kpi.history"].create(
self._generate_history_vals(value)
)
notifications = []
for dashboard_item in self.dashboard_item_ids:
channel = "kpi_dashboard_%s" % dashboard_item.dashboard_id.id
@ -115,6 +155,20 @@ class KpiKpi(models.Model):
self.env.cr.execute("rollback to %s" % savepoint)
return results.get("result", {})
def show_value(self):
self.ensure_one()
action = self.env.ref('kpi_dashboard.kpi_kpi_act_window')
result = action.read()[0]
result.update({
'res_id': self.id,
'target': 'new',
'view_mode': 'form',
'views': [(self.env.ref(
'kpi_dashboard.kpi_kpi_widget_form_view'
).id, 'form')],
})
return result
class KpiKpiAction(models.Model):
_name = 'kpi.kpi.action'
@ -139,3 +193,37 @@ class KpiKpiAction(models.Model):
'name': r.action.name
})
return result
class KpiKpiHistory(models.Model):
_name = 'kpi.kpi.history'
_description = 'KPI history'
_order = 'create_date DESC'
kpi_id = fields.Many2one(
'kpi.kpi', required=True, ondelete='cascade', readonly=True
)
value = fields.Serialized(readonly=True)
raw_value = fields.Char(compute='_compute_raw_value')
name = fields.Char(related='kpi_id.name')
widget = fields.Selection(
selection=lambda self:
self.env['kpi.kpi']._fields['widget'].selection,
required=True)
@api.depends('value')
def _compute_raw_value(self):
for record in self:
record.raw_value = json.dumps(record.value)
def show_form(self):
self.ensure_one()
action = self.env.ref('kpi_dashboard.kpi_kpi_history_act_window')
result = action.read()[0]
result.update({
'res_id': self.id,
'target': 'new',
'view_mode': 'form',
'views': [(self.env.context.get('form_id'), 'form')],
})
return result

2
kpi_dashboard/security/ir.model.access.csv

@ -3,7 +3,9 @@ access_kpi_dashboard,access_kpi_dashboard,model_kpi_dashboard,base.group_user,1,
access_kpi_dashboard_kpi,access_kpi_dashboard_kpi,model_kpi_dashboard_item,base.group_user,1,0,0,0
access_kpi_kpi,access_kpi_kpi,model_kpi_kpi,base.group_user,1,0,0,0
access_kpi_kpi_action,access_kpi_kpi_action,model_kpi_kpi_action,base.group_user,1,0,0,0
access_kpi_kpi_history,access_kpi_kpi_history,model_kpi_kpi_history,base.group_user,1,0,0,0
manage_kpi_dashboard,manage_kpi_dashboard,model_kpi_dashboard,group_kpi_dashboard_manager,1,1,1,1
manage_kpi_dashboard_kpi,manage_kpi_dashboard_kpi,model_kpi_dashboard_item,group_kpi_dashboard_manager,1,1,1,1
manage_kpi_kpi,manage_kpi_kpi,model_kpi_kpi,group_kpi_dashboard_manager,1,1,1,1
manage_kpi_kpi_action,manage_kpi_kpi_action,model_kpi_kpi_action,group_kpi_dashboard_manager,1,1,1,1
manage_kpi_kpi_history,manage_kpi_kpi_history,model_kpi_kpi_history,group_kpi_dashboard_manager,1,1,1,1

68
kpi_dashboard/static/src/js/field_widget.js

@ -0,0 +1,68 @@
odoo.define('kpi_dashboard.KpiFieldWidget', function(require) {
"use strict";
var basic_fields = require('web.basic_fields');
var field_registry = require('web.field_registry');
var core = require('web.core');
var qweb = core.qweb;
var registry = require('kpi_dashboard.widget_registry');
var KpiFieldWidget = basic_fields.FieldChar.extend({
jsLibs: [
'/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.js',
],
cssLibs: [
'/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.css',
],
className: 'o_dashboard_view',
_renderReadonly: function () {
this.$el.html($(qweb.render('dashboard_kpi.dashboard')));
var marginx = 0;
var marginy = 0;
var widgetx = 400;
var widgety = 400;
this.$el.find('.gridster').css('width', widgety);
this.$grid = this.$el.find('.gridster ul');
var widgetVals = {
value: this.value,
col: 1,
row: 1,
sizex: 1,
sizey: 1,
name: this.recordData[this.nodeOptions.name],
value_last_update: this.recordData[this.nodeOptions.date]
}
var Widget = registry.getAny([
this.recordData[this.nodeOptions.widget], 'abstract',
]);
this.state = {
specialData: {
margin_x: marginx,
margin_y: marginy,
widget_dimension_x: widgetx,
widget_dimension_y: widgety,
}
}
var widget = new Widget(this, widgetVals);
var element = $(qweb.render(
'kpi_dashboard.kpi', {widget: widgetVals}));
element.css('background-color', 'white');
element.css('color', 'black');
this.$grid.append(element);
widget.appendTo(element)
this.$grid.gridster({
widget_margins: [
marginx,
marginy,
],
widget_base_dimensions: [
widgetx,
widgety,
],
cols: 1,
}).data('gridster').disable();
},
});
field_registry.add('kpi', KpiFieldWidget);
return KpiFieldWidget;
});

22
kpi_dashboard/tests/test_formula.py

@ -57,3 +57,25 @@ result['previous'] = len(model.search([('id', '!=', %s)]))
self.assertTrue(value.get("value"))
self.assertEqual(value.get("value"), 1)
self.assertEqual(value.get("previous"), self.kpi.search_count([]) - 1)
self.assertFalse(self.kpi.history_ids)
def test_computation_history(self):
self.assertFalse(self.kpi.value)
self.kpi.store_history = True
self.kpi.compute()
self.assertTrue(self.kpi.history_ids)
self.assertEqual(self.kpi.value, {})
self.kpi.code = """
result = {}
result['value'] = len(model.search([('id', '=', %s)]))
result['previous'] = len(model.search([('id', '!=', %s)]))
""" % (
self.kpi.id,
self.kpi.id,
)
self.kpi.compute()
value = self.kpi.value
self.assertTrue(value.get("value"))
self.assertEqual(value.get("value"), 1)
self.assertEqual(value.get("previous"), self.kpi.search_count([]) - 1)
self.assertTrue(self.kpi.history_ids)

83
kpi_dashboard/views/kpi_kpi.xml

@ -4,6 +4,55 @@
<odoo>
<record model="ir.actions.act_window" id="kpi_kpi_history_act_window">
<field name="name">Kpi History</field>
<field name="res_model">kpi.kpi.history</field>
<field name="view_mode">tree</field>
<field name="domain">[('kpi_id', '=', active_id)]</field>
<field name="context">{}</field>
</record>
<record model="ir.ui.view" id="kpi_kpi_history_widget_form_view">
<field name="name">kpi.kpi.history.raw.form (in kpi_dashboard)</field>
<field name="model">kpi.kpi.history</field>
<field name="arch" type="xml">
<form>
<field name="create_date" invisible="1"/>
<field name="widget" invisible="1"/>
<field name="name" invisible="1"/>
<field name="value"
widget="kpi"
options="{'date': 'create_date', 'widget': 'widget', 'name': 'name'}"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="kpi_kpi_history_raw_form_view">
<field name="name">kpi.kpi.history.raw.form (in kpi_dashboard)</field>
<field name="model">kpi.kpi.history</field>
<field name="arch" type="xml">
<form>
<field name="raw_value"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="kpi_kpi_history_tree_view">
<field name="name">kpi.kpi.history.tree (in kpi_dashboard)</field>
<field name="model">kpi.kpi.history</field>
<field name="arch" type="xml">
<tree create="0" delete="0">
<field name="create_date"/>
<button name="show_form" string="Show value" type="object"
context="{'form_id': %(kpi_dashboard.kpi_kpi_history_widget_form_view)d}"
/>
<button name="show_form" string="Raw value" type="object"
context="{'form_id': %(kpi_dashboard.kpi_kpi_history_raw_form_view)d}"
/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="kpi_kpi_form_view">
<field name="name">kpi.kpi.form (in kpi_dashboard)</field>
<field name="model">kpi.kpi</field>
@ -11,11 +60,20 @@
<form>
<header>
<button name="generate_cron" string="Generate cron" type="object"
attrs="{'invisible': [('cron_id', '!=',False)]}"/>
<button name="compute" string="Compute now" type="object"/>
attrs="{'invisible': ['|', ('cron_id', '!=',False), ('compute_on_fly', '=', True)]}"/>
<button name="compute" string="Compute now" type="object" attrs="{'invisible': [('compute_on_fly', '=', True)]}"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box"/>
<div class="oe_button_box" name="button_box">
<button name="%(kpi_dashboard.kpi_kpi_history_act_window)d"
string="Show history"
type="action"
attrs="{'invisible': ['|', ('store_history', '=', False), ('compute_on_fly', '=', True)]}"
icon="fa-history"/>
<button string="Show value" type="object" name="show_value"
icon="fa-paint-brush"
/>
</div>
<h2>
<field name="name"/>
</h2>
@ -23,6 +81,10 @@
<group>
<field name="computation_method"/>
<field name="widget"/>
<field name="store_history" attrs="{'invisible': [('compute_on_fly', '=', True)]}"/>
<field name="store_history_interval" attrs="{'invisible': [('store_history', '=', False)]}"/>
<field name="store_history_interval_number" attrs="{'invisible': [('store_history', '=', False)]}"/>
<field name="compute_on_fly" attrs="{'invisible': [('store_history', '=', True)]}"/>
<field name="model_id" attrs="{'invisible': [('computation_method', '!=', 'function')]}"/>
<field name="function" attrs="{'required': [('computation_method', '=', 'function')], 'invisible': [('computation_method', '!=', 'function')]}"/>
<field name="args" attrs="{'invisible': [('computation_method', '!=', 'function')]}"/>
@ -56,6 +118,21 @@
</field>
</record>
<record model="ir.ui.view" id="kpi_kpi_widget_form_view">
<field name="name">kpi.kpi.raw.form (in kpi_dashboard)</field>
<field name="model">kpi.kpi</field>
<field name="arch" type="xml">
<form>
<field name="computed_date" invisible="1"/>
<field name="widget" invisible="1"/>
<field name="name" invisible="1"/>
<field name="computed_value"
widget="kpi"
options="{'date': 'computed_date', 'widget': 'widget', 'name': 'name'}"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="kpi_kpi_search_view">
<field name="name">kpi.kpi.search (in kpi_dashboard)</field>
<field name="model">kpi.kpi</field>

1
kpi_dashboard/views/webclient_templates.xml

@ -18,6 +18,7 @@
<script type="text/javascript" src="/kpi_dashboard/static/src/js/widget/meter_widget.js"/>
<script type="text/javascript" src="/kpi_dashboard/static/src/js/widget/graph_widget.js"/>
<script type="text/javascript" src="/kpi_dashboard/static/src/js/widget/text_widget.js"/>
<script type="text/javascript" src="/kpi_dashboard/static/src/js/field_widget.js"/>
<link rel="stylesheet" type="text/scss" href="/kpi_dashboard/static/src/scss/kpi_dashboard.scss"/>
</xpath>

Loading…
Cancel
Save