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` #. Meter: result must contain `value`, `min` and `max`
#. Graph: result must contain a list on `graphs` containing `values`, `title` and `key` #. 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 Configure dashboards
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~

1
kpi_dashboard/__manifest__.py

@ -20,4 +20,5 @@
"views/kpi_kpi.xml", "views/kpi_kpi.xml",
"views/kpi_dashboard.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 #. In order to compute the KPI you can use a predefined function from a model or
use the code to directly compute it. 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 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"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <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> <title>Kpi Dashboard</title>
<style type="text/css"> <style type="text/css">
@ -374,14 +374,15 @@ ul.auto-toc {
<ul class="simple"> <ul class="simple">
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a><ul> <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-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> </ul>
</li> </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> </ul>
</li> </li>
</ul> </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> <li>Graph: result must contain a list on <cite>graphs</cite> containing <cite>values</cite>, <cite>title</cite> and <cite>key</cite></li>
</ol> </ol>
</li> </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> </ol>
</div> </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"> <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"> <ol class="arabic simple">
<li>Access <cite>Dashboards &gt; Configuration &gt; KPI Dashboards &gt; Configure Dashboards</cite></li> <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> <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> </div>
<div class="section" id="bug-tracker"> <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>. <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. 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 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> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <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"> <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"> <ul class="simple">
<li>Creu Blanca</li> <li>Creu Blanca</li>
</ul> </ul>
</div> </div>
<div class="section" id="contributors"> <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"> <ul class="simple">
<li>Enric Tobella &lt;<a class="reference external" href="mailto:etobella&#64;creublanca.es">etobella&#64;creublanca.es</a>&gt;</li> <li>Enric Tobella &lt;<a class="reference external" href="mailto:etobella&#64;creublanca.es">etobella&#64;creublanca.es</a>&gt;</li>
</ul> </ul>
</div> </div>
<div class="section" id="maintainers"> <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> <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> <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 <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_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