Browse Source

[12.0][IMP] kpi_dashboard: Add demo data and testing

12.0
Enric Tobella 4 years ago
parent
commit
bbe73a0063
  1. 12
      kpi_dashboard/README.rst
  2. 1
      kpi_dashboard/__manifest__.py
  3. 157
      kpi_dashboard/demo/demo_dashboard.xml
  4. 11
      kpi_dashboard/readme/CONFIGURE.rst
  5. 38
      kpi_dashboard/static/description/index.html
  6. 1
      kpi_dashboard/tests/__init__.py
  7. 161
      kpi_dashboard/tests/test_kpi_dashboard.py

12
kpi_dashboard/README.rst

@ -45,6 +45,18 @@ Configure KPIs
#. Meter: result must contain `value`, `min` and `max`
#. Graph: result must contain a list on `graphs` containing `values`, `title` and `key`
#. In order to compute the KPI you can use a predefined function from a model or
use the code to directly compute it.
Using KPI with code
~~~~~~~~~~~~~~~~~~~
Define the code directly on the code field. You can use:
* `self` and `model` as the kpi element
* The script should create a variable called `result` as a dictionary that
will be stored as the value
Configure dashboards
~~~~~~~~~~~~~~~~~~~~

1
kpi_dashboard/__manifest__.py

@ -20,4 +20,5 @@
"views/kpi_kpi.xml",
"views/kpi_dashboard.xml",
],
"demo": ["demo/demo_dashboard.xml"],
}

157
kpi_dashboard/demo/demo_dashboard.xml

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="demo_dashboard" model="kpi.dashboard">
<field name="name">Dashboard</field>
<field name="number_of_columns">4</field>
<field name="widget_dimension_y">50</field>
<field name="widget_dimension_x">250</field>
<field name="background_color">#020202</field>
</record>
<record id="widget_number_01" model="kpi.kpi">
<field name="name">Number 01</field>
<field name="prefix">$</field>
<field name="computation_method">code</field>
<field name="widget">number</field>
<field name="code">
result = {"value": 10000,"previous": 12000}
</field>
</record>
<record id="widget_number_02" model="kpi.kpi">
<field name="name">Number 02</field>
<field name="suffix"></field>
<field name="computation_method">code</field>
<field name="widget">number</field>
<field name="code">
result = {"value": 12000,"previous": 10000}
</field>
</record>
<function model="kpi.kpi" name="compute"
eval="[[ref('widget_number_01'), ref('widget_number_02')]]"/>
<record id="widget_meter_01" model="kpi.kpi">
<field name="name">Meter 01</field>
<field name="suffix"></field>
<field name="computation_method">code</field>
<field name="widget">meter</field>
<field name="code">
result = {"min": 0, "max": 100, "value": 90}
</field>
</record>
<record id="widget_meter_02" model="kpi.kpi">
<field name="name">Meter 02</field>
<field name="prefix">$</field>
<field name="computation_method">code</field>
<field name="widget">meter</field>
<field name="code">
result = {"min": 0, "max": 100, "value": 40}
</field>
</record>
<function model="kpi.kpi" name="compute"
eval="[[ref('widget_meter_01'), ref('widget_meter_02')]]"/>
<record id="widget_graph" model="kpi.kpi">
<field name="name">Graph</field>
<field name="computation_method">code</field>
<field name="widget">graph</field>
<field name="code">
result = {"graphs": [
{
"values": [
{"x": i, "y": i * 1000}
for i in range(1, 12)
],
"title": "Current Year",
"key": "current",
"area": True,
"color": "ffffff",
},
{
"values": [
{"x": i, "y": 1000 * (12-i)}
for i in range(1, 12)
],
"title": "Previous Year",
"key": "previous",
"area": True,
"color": "000000",
},
]}
</field>
</record>
<function model="kpi.kpi" name="compute"
eval="[[ref('widget_graph')]]"/>
<record id="dashboard_widget_text" model="kpi.dashboard.item">
<field name="name">Dashboard title</field>
<field name="dashboard_id" ref="demo_dashboard"/>
<field name="column">1</field>
<field name="row">1</field>
<field name="size_x">4</field>
<field name="color">#707070</field>
<field name="font_color">#000000</field>
</record>
<record id="dashboard_widget_number_01" model="kpi.dashboard.item">
<field name="name">Number 01</field>
<field name="dashboard_id" ref="demo_dashboard"/>
<field name="kpi_id" ref="widget_number_01"/>
<field name="column">1</field>
<field name="row">2</field>
<field name="size_y">4</field>
<field name="color">#47bbb3</field>
<field name="font_color">#ffffff</field>
</record>
<record id="dashboard_widget_number_02" model="kpi.dashboard.item">
<field name="name">Number 02</field>
<field name="dashboard_id" ref="demo_dashboard"/>
<field name="kpi_id" ref="widget_number_02"/>
<field name="column">1</field>
<field name="row">6</field>
<field name="size_y">4</field>
<field name="color">#ec663c</field>
<field name="font_color">#ffffff</field>
</record>
<record id="dashboard_widget_meter_01" model="kpi.dashboard.item">
<field name="name">Meter 01</field>
<field name="dashboard_id" ref="demo_dashboard"/>
<field name="kpi_id" ref="widget_meter_01"/>
<field name="column">2</field>
<field name="row">2</field>
<field name="size_y">4</field>
<field name="color">#9c4274</field>
<field name="font_color">#ffffff</field>
</record>
<record id="dashboard_widget_meter_02" model="kpi.dashboard.item">
<field name="name">Meter 02</field>
<field name="dashboard_id" ref="demo_dashboard"/>
<field name="kpi_id" ref="widget_meter_02"/>
<field name="column">2</field>
<field name="row">6</field>
<field name="size_y">4</field>
<field name="color">#12b0c5</field>
<field name="font_color">#ffffff</field>
</record>
<record id="dashboard_widget_graph" model="kpi.dashboard.item">
<field name="name">Graph</field>
<field name="dashboard_id" ref="demo_dashboard"/>
<field name="kpi_id" ref="widget_graph"/>
<field name="column">3</field>
<field name="row">2</field>
<field name="size_x">2</field>
<field name="size_y">8</field>
<field name="color">#ff9618</field>
<field name="font_color">#ffffff</field>
</record>
</odoo>

11
kpi_dashboard/readme/CONFIGURE.rst

@ -11,6 +11,17 @@ Configure KPIs
#. In order to compute the KPI you can use a predefined function from a model or
use the code to directly compute it.
Using KPI with code
~~~~~~~~~~~~~~~~~~~
Define the code directly on the code field. You can use `self` and `model` as the kpi element
The script should create a variable called `result` as a dictionary that
will be stored as the value.
For example, we can use::
result = {}
result['value'] = len(model.search([('id', '=', %s)]))
result['previous'] = len(model.search([('id', '!=', %s)]))
Configure dashboards
~~~~~~~~~~~~~~~~~~~~

38
kpi_dashboard/static/description/index.html

@ -3,7 +3,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" />
<title>Kpi Dashboard</title>
<style type="text/css">
@ -374,14 +374,15 @@ ul.auto-toc {
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a><ul>
<li><a class="reference internal" href="#configure-kpis" id="id2">Configure KPIs</a></li>
<li><a class="reference internal" href="#configure-dashboards" id="id3">Configure dashboards</a></li>
<li><a class="reference internal" href="#using-kpi-with-code" id="id3">Using KPI with code</a></li>
<li><a class="reference internal" href="#configure-dashboards" id="id4">Configure dashboards</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="id4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id8">Maintainers</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id5">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id6">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id7">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id8">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id9">Maintainers</a></li>
</ul>
</li>
</ul>
@ -398,10 +399,21 @@ ul.auto-toc {
<li>Graph: result must contain a list on <cite>graphs</cite> containing <cite>values</cite>, <cite>title</cite> and <cite>key</cite></li>
</ol>
</li>
<li>In order to compute the KPI you can use a predefined function from a model or
use the code to directly compute it.</li>
</ol>
</div>
<div class="section" id="using-kpi-with-code">
<h2><a class="toc-backref" href="#id3">Using KPI with code</a></h2>
<p>Define the code directly on the code field. You can use:</p>
<ul class="simple">
<li><cite>self</cite> and <cite>model</cite> as the kpi element</li>
<li>The script should create a variable called <cite>result</cite> as a dictionary that
will be stored as the value</li>
</ul>
</div>
<div class="section" id="configure-dashboards">
<h2><a class="toc-backref" href="#id3">Configure dashboards</a></h2>
<h2><a class="toc-backref" href="#id4">Configure dashboards</a></h2>
<ol class="arabic simple">
<li>Access <cite>Dashboards &gt; Configuration &gt; KPI Dashboards &gt; Configure Dashboards</cite></li>
<li>Create a new dashboard and specify all the standard parameters on <cite>Widget configuration</cite></li>
@ -412,7 +424,7 @@ ul.auto-toc {
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id4">Bug Tracker</a></h1>
<h1><a class="toc-backref" href="#id5">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/reporting-engine/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
@ -420,21 +432,21 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id5">Credits</a></h1>
<h1><a class="toc-backref" href="#id6">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id6">Authors</a></h2>
<h2><a class="toc-backref" href="#id7">Authors</a></h2>
<ul class="simple">
<li>Creu Blanca</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id7">Contributors</a></h2>
<h2><a class="toc-backref" href="#id8">Contributors</a></h2>
<ul class="simple">
<li>Enric Tobella &lt;<a class="reference external" href="mailto:etobella&#64;creublanca.es">etobella&#64;creublanca.es</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id8">Maintainers</a></h2>
<h2><a class="toc-backref" href="#id9">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose

1
kpi_dashboard/tests/__init__.py

@ -1 +1,2 @@
from . import test_formula
from . import test_kpi_dashboard

161
kpi_dashboard/tests/test_kpi_dashboard.py

@ -0,0 +1,161 @@
# Copyright 2020 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError
from odoo.tests.common import Form
from mock import patch
class TestKpiDashboard(TransactionCase):
def setUp(self):
super(TestKpiDashboard, self).setUp()
self.kpi_01 = self.env['kpi.kpi'].create({
'name': 'KPI 01',
'computation_method': 'function',
'widget': 'number',
'function': 'test_demo_number'
})
self.kpi_02 = self.env['kpi.kpi'].create({
'name': 'KPI 02',
'computation_method': 'function',
'widget': 'number',
'function': 'test_demo_number'
})
self.dashboard = self.env['kpi.dashboard'].create({
'name': 'Dashboard',
'number_of_columns': 4,
'widget_dimension_x': 250,
'widget_dimension_y': 250,
})
self.env['kpi.dashboard.item'].create({
'dashboard_id': self.dashboard.id,
'kpi_id': self.kpi_01.id,
'name': self.kpi_01.name,
'row': 1,
'column': 1,
})
self.env['kpi.dashboard.item'].create({
'dashboard_id': self.dashboard.id,
'name': self.kpi_02.name,
'kpi_id': self.kpi_02.id,
'row': 1,
'column': 2,
})
self.env['kpi.dashboard.item'].create({
'dashboard_id': self.dashboard.id,
'name': 'TITLE',
'row': 2,
'column': 1,
})
def test_constrains_01(self):
with self.assertRaises(ValidationError):
self.kpi_01.dashboard_item_ids.write({'size_x': 2})
def test_constrains_02(self):
with self.assertRaises(ValidationError):
self.kpi_02.dashboard_item_ids.write({'size_x': 4})
def test_constrains_03(self):
with self.assertRaises(ValidationError):
self.kpi_01.dashboard_item_ids.write({'size_y': 11})
def test_menu(self):
self.assertFalse(self.dashboard.menu_id)
wzd = self.env['kpi.dashboard.menu'].create({
'dashboard_id': self.dashboard.id,
'menu_id': self.env['ir.ui.menu'].search([], limit=1).id,
})
wzd.generate_menu()
self.assertTrue(self.dashboard.menu_id)
self.assertFalse(self.dashboard.menu_id.groups_id)
self.dashboard.write({
'group_ids': [
(6, 0, self.env['res.groups'].search([], limit=1).ids)]
})
self.assertTrue(self.dashboard.menu_id.groups_id)
def test_onchange(self):
with Form(self.env['kpi.dashboard']) as dashboard:
dashboard.name = 'New Dashboard'
with dashboard.item_ids.new() as item:
item.kpi_id = self.kpi_01
self.assertTrue(item.name)
def test_read_dashboard(self):
data = self.dashboard.read_dashboard()
title_found = False
actions = 0
for item in data['item_ids']:
if not item.get('kpi_id'):
title_found = True
if item.get('actions', False):
actions += len(item['actions'])
self.assertTrue(title_found)
self.assertEqual(0, actions)
act01 = self.env['ir.actions.act_window'].search(
[], limit=1)
self.env['kpi.kpi.action'].create({
'kpi_id': self.kpi_01.id,
'action': '%s,%s' % (act01._name, act01.id)
})
act02 = self.env['ir.actions.act_url'].search(
[], limit=1)
self.env['kpi.kpi.action'].create({
'kpi_id': self.kpi_01.id,
'action': '%s,%s' % (act02._name, act02.id)
})
data = self.dashboard.read_dashboard()
title_found = False
actions = 0
for item in data['item_ids']:
if not item.get('kpi_id'):
title_found = True
if item.get('actions', False):
actions += len(item['actions'])
self.assertTrue(title_found)
self.assertEqual(2, actions)
self.assertFalse(data.get("action_id", False))
wzd = self.env['kpi.dashboard.menu'].create({
'dashboard_id': self.dashboard.id,
'menu_id': self.env['ir.ui.menu'].search([], limit=1).id,
})
wzd.generate_menu()
data = self.dashboard.read_dashboard()
self.assertTrue(data.get("action_id", False))
def test_compute(self):
self.assertFalse(self.kpi_01.value_last_update)
with patch(
"odoo.addons.kpi_dashboard.models.kpi_kpi."
"KpiKpi.test_demo_number", create=True
) as f:
f.return_value = {"value": 0}
self.kpi_01.compute()
self.assertTrue(self.kpi_01.value_last_update)
def test_compute_model(self):
self.assertFalse(self.kpi_01.value_last_update)
self.kpi_01.model_id = self.env.ref('base.model_res_partner')
with patch(
"odoo.addons.base.models.res_partner.Partner.test_demo_number",
create=True
) as f:
f.return_value = {"value": 0}
self.kpi_01.compute()
self.assertTrue(self.kpi_01.value_last_update)
def test_generate_cron(self):
self.assertFalse(self.kpi_01.cron_id)
self.kpi_01.generate_cron()
self.assertTrue(self.kpi_01.cron_id)
self.assertFalse(self.kpi_01.value_last_update)
with patch(
"odoo.addons.kpi_dashboard.models.kpi_kpi."
"KpiKpi.test_demo_number", create=True
) as f:
f.return_value = {"value": 0}
self.kpi_01.cron_id.method_direct_trigger()
self.assertTrue(self.kpi_01.value_last_update)
Loading…
Cancel
Save