[IMP] kpi_dashboard: Set history & Add compute on the fly & Show value on kpi computation
parent
04e6f90ecc
commit
1fc11e9398
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
|
@ -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;
|
||||
});
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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…
Reference in New Issue