Browse Source

[MIG] kpi_dashboard: Migration to 14.0

myc-14.0-py3o
Enric Tobella 4 years ago
parent
commit
c0474fa9a7
  1. 2
      kpi_dashboard/__manifest__.py
  2. 46
      kpi_dashboard/demo/demo_dashboard.xml
  3. 4
      kpi_dashboard/models/ir_actions_act_window_view.py
  4. 4
      kpi_dashboard/models/ir_ui_view.py
  5. 15
      kpi_dashboard/models/kpi_dashboard.py
  6. 13
      kpi_dashboard/models/kpi_kpi.py
  7. 1
      kpi_dashboard/security/ir.model.access.csv
  8. 7
      kpi_dashboard/security/security.xml
  9. 38
      kpi_dashboard/static/src/js/dashboard_controller.js
  10. 6
      kpi_dashboard/static/src/js/dashboard_model.js
  11. 18
      kpi_dashboard/static/src/js/dashboard_renderer.js
  12. 4
      kpi_dashboard/static/src/js/dashboard_view.js
  13. 4
      kpi_dashboard/static/src/js/field_widget.js
  14. 10
      kpi_dashboard/static/src/js/lib/nvd3.js
  15. 22
      kpi_dashboard/static/src/js/widget/abstract_widget.js
  16. 2
      kpi_dashboard/static/src/js/widget/counter_widget.js
  17. 28
      kpi_dashboard/static/src/js/widget/graph_widget.js
  18. 8
      kpi_dashboard/static/src/js/widget/integer_widget.js
  19. 6
      kpi_dashboard/static/src/js/widget/meter_widget.js
  20. 4
      kpi_dashboard/static/src/js/widget/number_widget.js
  21. 4
      kpi_dashboard/static/src/js/widget/text_widget.js
  22. 2
      kpi_dashboard/static/src/js/widget_registry.js
  23. 5
      kpi_dashboard/static/src/xml/dashboard.xml
  24. 6
      kpi_dashboard/tests/test_formula.py
  25. 2
      kpi_dashboard/views/kpi_dashboard.xml

2
kpi_dashboard/__manifest__.py

@ -5,7 +5,7 @@
"name": "Kpi Dashboard", "name": "Kpi Dashboard",
"summary": """ "summary": """
Create Dashboards using kpis""", Create Dashboards using kpis""",
"version": "13.0.1.0.0",
"version": "14.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Creu Blanca,Odoo Community Association (OCA)", "author": "Creu Blanca,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/reporting-engine", "website": "https://github.com/OCA/reporting-engine",

46
kpi_dashboard/demo/demo_dashboard.xml

@ -13,18 +13,14 @@
<field name="prefix">$</field> <field name="prefix">$</field>
<field name="computation_method">code</field> <field name="computation_method">code</field>
<field name="widget">number</field> <field name="widget">number</field>
<field name="code">
result = {"value": 10000,"previous": 12000}
</field>
<field name="code">result = {"value": 10000,"previous": 12000}</field>
</record> </record>
<record id="widget_number_02" model="kpi.kpi"> <record id="widget_number_02" model="kpi.kpi">
<field name="name">Number 02</field> <field name="name">Number 02</field>
<field name="suffix"></field> <field name="suffix"></field>
<field name="computation_method">code</field> <field name="computation_method">code</field>
<field name="widget">number</field> <field name="widget">number</field>
<field name="code">
result = {"value": 12000,"previous": 10000}
</field>
<field name="code">result = {"value": 12000,"previous": 10000}</field>
</record> </record>
<function <function
model="kpi.kpi" model="kpi.kpi"
@ -36,18 +32,14 @@ result = {"value": 12000,"previous": 10000}
<field name="suffix"></field> <field name="suffix"></field>
<field name="computation_method">code</field> <field name="computation_method">code</field>
<field name="widget">meter</field> <field name="widget">meter</field>
<field name="code">
result = {"min": 0, "max": 100, "value": 90}
</field>
<field name="code">result = {"min": 0, "max": 100, "value": 90}</field>
</record> </record>
<record id="widget_meter_02" model="kpi.kpi"> <record id="widget_meter_02" model="kpi.kpi">
<field name="name">Meter 02</field> <field name="name">Meter 02</field>
<field name="prefix">$</field> <field name="prefix">$</field>
<field name="computation_method">code</field> <field name="computation_method">code</field>
<field name="widget">meter</field> <field name="widget">meter</field>
<field name="code">
result = {"min": 0, "max": 100, "value": 40}
</field>
<field name="code">result = {"min": 0, "max": 100, "value": 40}</field>
</record> </record>
<function <function
model="kpi.kpi" model="kpi.kpi"
@ -58,7 +50,9 @@ result = {"min": 0, "max": 100, "value": 40}
<field name="name">Graph</field> <field name="name">Graph</field>
<field name="computation_method">code</field> <field name="computation_method">code</field>
<field name="widget">graph</field> <field name="widget">graph</field>
<field name="code">
<field
name="code"
><![CDATA[
result = {"graphs": [ result = {"graphs": [
{ {
"values": [ "values": [
@ -81,7 +75,7 @@ result = {"graphs": [
"color": "000000", "color": "000000",
}, },
]} ]}
</field>
]]></field>
</record> </record>
<function model="kpi.kpi" name="compute" eval="[[ref('widget_graph')]]" /> <function model="kpi.kpi" name="compute" eval="[[ref('widget_graph')]]" />
<record id="widget_integer" model="kpi.kpi"> <record id="widget_integer" model="kpi.kpi">
@ -89,18 +83,22 @@ result = {"graphs": [
<field name="computation_method">code</field> <field name="computation_method">code</field>
<field name="widget">integer</field> <field name="widget">integer</field>
<field name="compute_on_fly" eval="True" /> <field name="compute_on_fly" eval="True" />
<field name="code">
<field
name="code"
><![CDATA[
result = {"value": self.env.context.get('counter', 990)} result = {"value": self.env.context.get('counter', 990)}
</field>
]]></field>
</record> </record>
<record id="widget_counter" model="kpi.kpi"> <record id="widget_counter" model="kpi.kpi">
<field name="name">Counter</field> <field name="name">Counter</field>
<field name="computation_method">code</field> <field name="computation_method">code</field>
<field name="widget">counter</field> <field name="widget">counter</field>
<field name="compute_on_fly" eval="True" /> <field name="compute_on_fly" eval="True" />
<field name="code">
<field
name="code"
><![CDATA[
result = {"value": self.env.context.get('counter', 990)} result = {"value": self.env.context.get('counter', 990)}
</field>
]]></field>
</record> </record>
<record id="dashboard_widget_text" model="kpi.dashboard.item"> <record id="dashboard_widget_text" model="kpi.dashboard.item">
<field name="name">Dashboard title</field> <field name="name">Dashboard title</field>
@ -161,13 +159,13 @@ result = {"value": self.env.context.get('counter', 990)}
<field name="color">#B41F1F</field> <field name="color">#B41F1F</field>
<field name="font_color">#EEBF77</field> <field name="font_color">#EEBF77</field>
<field name="modify_context" eval="True" /> <field name="modify_context" eval="True" />
<field
name="modify_context_expression"
>{'counter': (context.counter or 990) + 1}</field>
<field name="modify_context_expression">
{'counter': (context.counter or 990) + 1}
</field>
<field name="modify_color" eval="True" /> <field name="modify_color" eval="True" />
<field
name="modify_color_expression"
>check_if(((context.counter or 990) + 1) % 2, '#ff0000', '#00ff00')</field>
<field name="modify_color_expression">
check_if(((context.counter or 990) + 1) % 2, '#ff0000', '#00ff00')
</field>
</record> </record>
<record id="dashboard_widget_counter" model="kpi.dashboard.item"> <record id="dashboard_widget_counter" model="kpi.dashboard.item">
<field name="name">Counter</field> <field name="name">Counter</field>

4
kpi_dashboard/models/ir_actions_act_window_view.py

@ -7,4 +7,6 @@ from odoo import fields, models
class IrActionsActWindowView(models.Model): class IrActionsActWindowView(models.Model):
_inherit = "ir.actions.act_window.view" _inherit = "ir.actions.act_window.view"
view_mode = fields.Selection(selection_add=[("dashboard", "Dashboard")])
view_mode = fields.Selection(
selection_add=[("dashboard", "Dashboard")], ondelete={"dashboard": "cascade"}
)

4
kpi_dashboard/models/ir_ui_view.py

@ -7,4 +7,6 @@ from odoo import fields, models
class IrUiView(models.Model): class IrUiView(models.Model):
_inherit = "ir.ui.view" _inherit = "ir.ui.view"
type = fields.Selection(selection_add=[("dashboard", "Dashboard")])
type = fields.Selection(
selection_add=[("dashboard", "Dashboard")], ondelete={"dashboard": "cascade"}
)

15
kpi_dashboard/models/kpi_dashboard.py

@ -11,9 +11,13 @@ class KpiDashboard(models.Model):
_description = "Dashboard" _description = "Dashboard"
name = fields.Char(required=True) name = fields.Char(required=True)
active = fields.Boolean(default=True,)
active = fields.Boolean(
default=True,
)
item_ids = fields.One2many( item_ids = fields.One2many(
"kpi.dashboard.item", inverse_name="dashboard_id", copy=True,
"kpi.dashboard.item",
inverse_name="dashboard_id",
copy=True,
) )
number_of_columns = fields.Integer(default=5, required=True) number_of_columns = fields.Integer(default=5, required=True)
compute_on_fly_refresh = fields.Integer( compute_on_fly_refresh = fields.Integer(
@ -25,7 +29,9 @@ class KpiDashboard(models.Model):
widget_dimension_x = fields.Integer(default=250, required=True) widget_dimension_x = fields.Integer(default=250, required=True)
widget_dimension_y = fields.Integer(default=250, required=True) widget_dimension_y = fields.Integer(default=250, required=True)
background_color = fields.Char(required=True, default="#f9f9f9") background_color = fields.Char(required=True, default="#f9f9f9")
group_ids = fields.Many2many("res.groups",)
group_ids = fields.Many2many(
"res.groups",
)
menu_id = fields.Many2one("ir.ui.menu", copy=False) menu_id = fields.Many2one("ir.ui.menu", copy=False)
def write(self, vals): def write(self, vals):
@ -227,3 +233,6 @@ class KpiDashboardItem(models.Model):
"kpi_dashboard.kpi_dashboard_item_config_form_view" "kpi_dashboard.kpi_dashboard_item_config_form_view"
).id, ).id,
} }
def store_data(self):
return {"type": "ir.actions.act_window_close"}

13
kpi_dashboard/models/kpi_kpi.py

@ -2,9 +2,9 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import ast import ast
import datetime
import json import json
import re import re
from datetime import date, datetime, time
from dateutil import relativedelta from dateutil import relativedelta
@ -24,11 +24,15 @@ class KpiKpi(models.Model):
active = fields.Boolean(default=True) active = fields.Boolean(default=True)
cron_id = fields.Many2one("ir.cron", readonly=True, copy=False) cron_id = fields.Many2one("ir.cron", readonly=True, copy=False)
computation_method = fields.Selection( computation_method = fields.Selection(
[("function", "Function"), ("code", "Code")], required=True
[("function", "Function"), ("code", "Code")],
required=True,
default="code",
) )
value = fields.Serialized() value = fields.Serialized()
dashboard_item_ids = fields.One2many("kpi.dashboard.item", inverse_name="kpi_id") dashboard_item_ids = fields.One2many("kpi.dashboard.item", inverse_name="kpi_id")
model_id = fields.Many2one("ir.model",)
model_id = fields.Many2one(
"ir.model",
)
function = fields.Char() function = fields.Char()
args = fields.Char() args = fields.Char()
kwargs = fields.Char() kwargs = fields.Char()
@ -144,6 +148,8 @@ class KpiKpi(models.Model):
"self": self, "self": self,
"model": self.browse(), "model": self.browse(),
"datetime": datetime, "datetime": datetime,
"date": date,
"time": time,
"float_compare": float_compare, "float_compare": float_compare,
"relativedelta": relativedelta.relativedelta, "relativedelta": relativedelta.relativedelta,
} }
@ -231,6 +237,7 @@ class KpiKpiHistory(models.Model):
widget = fields.Selection( widget = fields.Selection(
selection=lambda self: self.env["kpi.kpi"]._fields["widget"].selection, selection=lambda self: self.env["kpi.kpi"]._fields["widget"].selection,
required=True, required=True,
default="number",
) )
@api.depends("value") @api.depends("value")

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

@ -9,3 +9,4 @@ manage_kpi_dashboard_kpi,manage_kpi_dashboard_kpi,model_kpi_dashboard_item,group
manage_kpi_kpi,manage_kpi_kpi,model_kpi_kpi,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_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 manage_kpi_kpi_history,manage_kpi_kpi_history,model_kpi_kpi_history,group_kpi_dashboard_manager,1,1,1,1
access_kpi_dashboard_menu,access_kpi_dashboard_menu,model_kpi_dashboard_menu,group_kpi_dashboard_manager,1,1,1,1

7
kpi_dashboard/security/security.xml

@ -9,9 +9,10 @@
<record id="rule_kpi_dashboard" model="ir.rule"> <record id="rule_kpi_dashboard" model="ir.rule">
<field name="name">KPI Dashboard: User</field> <field name="name">KPI Dashboard: User</field>
<field name="model_id" ref="model_kpi_dashboard" /> <field name="model_id" ref="model_kpi_dashboard" />
<field
name="domain_force"
>['|', ('group_ids', '=', False), ('group_ids', 'in', user.groups_id.ids)]</field>
<field name="domain_force">
['|', ('group_ids', '=', False), ('group_ids', 'in',
user.groups_id.ids)]
</field>
<field name="groups" eval="[(4, ref('base.group_user'))]" /> <field name="groups" eval="[(4, ref('base.group_user'))]" />
</record> </record>
<record id="rule_kpi_dashboard_all" model="ir.rule"> <record id="rule_kpi_dashboard_all" model="ir.rule">

38
kpi_dashboard/static/src/js/dashboard_controller.js

@ -1,7 +1,7 @@
/* /*
global py global py
*/ */
odoo.define("kpi_dashboard.DashboardController", function(require) {
odoo.define("kpi_dashboard.DashboardController", function (require) {
"use strict"; "use strict";
var BasicController = require("web.BasicController"); var BasicController = require("web.BasicController");
@ -11,7 +11,7 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
var _t = core._t; var _t = core._t;
var DashboardController = BasicController.extend({ var DashboardController = BasicController.extend({
init: function() {
init: function () {
this._super.apply(this, arguments); this._super.apply(this, arguments);
this.dashboard_context = {}; this.dashboard_context = {};
this.dashboard_color_data = []; this.dashboard_color_data = [];
@ -23,15 +23,15 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
add_modify_color: "_addModifyColor", add_modify_color: "_addModifyColor",
refresh_colors: "_refreshColors", refresh_colors: "_refreshColors",
}), }),
_refreshOnFly: function() {
_refreshOnFly: function () {
var self = this; var self = this;
this._rpc({ this._rpc({
model: this.modelName, model: this.modelName,
method: "read_dashboard_on_fly", method: "read_dashboard_on_fly",
args: [[this.renderer.state.res_id]], args: [[this.renderer.state.res_id]],
context: this._getContext(), context: this._getContext(),
}).then(function(data) {
_.each(data, function(item) {
}).then(function (data) {
_.each(data, function (item) {
// We will follow the same logic used on Bus Notifications // We will follow the same logic used on Bus Notifications
self.renderer._onNotification([ self.renderer._onNotification([
["kpi_dashboard_" + self.renderer.state.res_id, item], ["kpi_dashboard_" + self.renderer.state.res_id, item],
@ -39,21 +39,21 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
}); });
}); });
}, },
renderPager: function($node, options) {
renderPager: function ($node, options) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
options = _.extend({}, options, { options = _.extend({}, options, {
validate: this.canBeDiscarded.bind(this), validate: this.canBeDiscarded.bind(this),
}); });
this._super($node, options); this._super($node, options);
}, },
_pushState: function(state) {
_pushState: function (state) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
state = state || {}; state = state || {};
var env = this.model.get(this.handle, {env: true}); var env = this.model.get(this.handle, {env: true});
state.id = env.currentId; state.id = env.currentId;
this._super(state); this._super(state);
}, },
_addDashboard: function() {
_addDashboard: function () {
var self = this; var self = this;
var action = self.initialState.specialData.action_id; var action = self.initialState.specialData.action_id;
var name = self.initialState.specialData.name; var name = self.initialState.specialData.name;
@ -71,7 +71,7 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
name: name, name: name,
}, },
}) })
.then(function(r) {
.then(function (r) {
if (r) { if (r) {
self.do_notify( self.do_notify(
_.str.sprintf(_t("'%s' added to dashboard"), name), _.str.sprintf(_t("'%s' added to dashboard"), name),
@ -84,7 +84,7 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
} }
}); });
}, },
_updateButtons: function() {
_updateButtons: function () {
// HOOK Function // HOOK Function
this.$buttons.on( this.$buttons.on(
"click", "click",
@ -92,7 +92,7 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
this._addDashboard.bind(this) this._addDashboard.bind(this)
); );
}, },
renderButtons: function($node) {
renderButtons: function ($node) {
if (!$node) { if (!$node) {
return; return;
} }
@ -103,7 +103,7 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
this._updateButtons(); this._updateButtons();
this.$buttons.appendTo($node); this.$buttons.appendTo($node);
}, },
_getContext: function() {
_getContext: function () {
return _.extend( return _.extend(
{}, {},
this.model.get(this.handle, {raw: true}).getContext(), this.model.get(this.handle, {raw: true}).getContext(),
@ -111,7 +111,7 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
this.dashboard_context this.dashboard_context
); );
}, },
_modifyContext: function(event) {
_modifyContext: function (event) {
var ctx = this._getContext(); var ctx = this._getContext();
this.dashboard_context = _.extend( this.dashboard_context = _.extend(
this.dashboard_context, this.dashboard_context,
@ -119,7 +119,7 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
context: _.extend( context: _.extend(
ctx, ctx,
{ {
__getattr__: function() {
__getattr__: function () {
return false; return false;
}, },
} }
@ -131,23 +131,23 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
this._refreshOnFly(event); this._refreshOnFly(event);
this._refreshColors(); this._refreshColors();
}, },
_addModifyColor: function(event) {
_addModifyColor: function (event) {
this.dashboard_color_data.push([ this.dashboard_color_data.push([
event.data.element_id, event.data.element_id,
event.data.expression, event.data.expression,
]); ]);
}, },
_refreshColors: function() {
_refreshColors: function () {
var self = this; var self = this;
var ctx = this._getContext(); var ctx = this._getContext();
_.each(this.dashboard_color_data, function(data) {
_.each(this.dashboard_color_data, function (data) {
var color = py.eval(data[1], { var color = py.eval(data[1], {
context: _.extend(ctx, { context: _.extend(ctx, {
__getattr__: function() {
__getattr__: function () {
return false; return false;
}, },
}), }),
check_if: function(args) {
check_if: function (args) {
if (args[0].toJSON()) { if (args[0].toJSON()) {
return args[1]; return args[1];
} }

6
kpi_dashboard/static/src/js/dashboard_model.js

@ -1,16 +1,16 @@
odoo.define("kpi_dashboard.DashboardModel", function(require) {
odoo.define("kpi_dashboard.DashboardModel", function (require) {
"use strict"; "use strict";
var BasicModel = require("web.BasicModel"); var BasicModel = require("web.BasicModel");
var DashboardModel = BasicModel.extend({ var DashboardModel = BasicModel.extend({
_fetchRecord: function(record) {
_fetchRecord: function (record) {
return this._rpc({ return this._rpc({
model: record.model, model: record.model,
method: "read_dashboard", method: "read_dashboard",
args: [[record.res_id]], args: [[record.res_id]],
context: _.extend({}, record.getContext(), {bin_size: true}), context: _.extend({}, record.getContext(), {bin_size: true}),
}).then(function(result) {
}).then(function (result) {
record.specialData = result; record.specialData = result;
return result; return result;
}); });

18
kpi_dashboard/static/src/js/dashboard_renderer.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.DashboardRenderer", function(require) {
odoo.define("kpi_dashboard.DashboardRenderer", function (require) {
"use strict"; "use strict";
var BasicRenderer = require("web.BasicRenderer"); var BasicRenderer = require("web.BasicRenderer");
@ -8,25 +8,25 @@ odoo.define("kpi_dashboard.DashboardRenderer", function(require) {
var DashboardRenderer = BasicRenderer.extend({ var DashboardRenderer = BasicRenderer.extend({
className: "o_dashboard_view", className: "o_dashboard_view",
_getDashboardWidget: function(kpi) {
_getDashboardWidget: function (kpi) {
var Widget = registry.getAny([kpi.widget, "abstract"]); var Widget = registry.getAny([kpi.widget, "abstract"]);
var widget = new Widget(this, kpi); var widget = new Widget(this, kpi);
return widget; return widget;
}, },
_onClickModifyContext: function(modify_context_expression, event) {
_onClickModifyContext: function (modify_context_expression, event) {
this.trigger_up("modify_context", { this.trigger_up("modify_context", {
context: modify_context_expression, context: modify_context_expression,
event: event, event: event,
}); });
}, },
_renderView: function() {
_renderView: function () {
this.$el.html($(qweb.render("dashboard_kpi.dashboard"))); this.$el.html($(qweb.render("dashboard_kpi.dashboard")));
this.$el.css("background-color", this.state.specialData.background_color); this.$el.css("background-color", this.state.specialData.background_color);
this.$el.find(".gridster").css("width", this.state.specialData.width); this.$el.find(".gridster").css("width", this.state.specialData.width);
this.$grid = this.$el.find(".gridster ul"); this.$grid = this.$el.find(".gridster ul");
var self = this; var self = this;
this.kpi_widget = {}; this.kpi_widget = {};
_.each(this.state.specialData.item_ids, function(kpi) {
_.each(this.state.specialData.item_ids, function (kpi) {
var element = $(qweb.render("kpi_dashboard.kpi", {widget: kpi})); var element = $(qweb.render("kpi_dashboard.kpi", {widget: kpi}));
element.css("background-color", kpi.color); element.css("background-color", kpi.color);
element.css("color", kpi.font_color); element.css("color", kpi.font_color);
@ -72,7 +72,7 @@ odoo.define("kpi_dashboard.DashboardRenderer", function(require) {
this.call("bus_service", "onNotification", this, this._onNotification); this.call("bus_service", "onNotification", this, this._onNotification);
if (this.state.specialData.compute_on_fly_refresh > 0) { if (this.state.specialData.compute_on_fly_refresh > 0) {
// Setting the refresh interval // Setting the refresh interval
this.on_fly_interval = setInterval(function() {
this.on_fly_interval = setInterval(function () {
self.trigger_up("refresh_on_fly"); self.trigger_up("refresh_on_fly");
}, this.state.specialData.compute_on_fly_refresh * 1000); }, this.state.specialData.compute_on_fly_refresh * 1000);
} }
@ -82,16 +82,16 @@ odoo.define("kpi_dashboard.DashboardRenderer", function(require) {
// context // context
return $.when(); return $.when();
}, },
on_detach_callback: function() {
on_detach_callback: function () {
// We want to clear the refresh interval once we exit the view // We want to clear the refresh interval once we exit the view
if (this.on_fly_interval) { if (this.on_fly_interval) {
clearInterval(this.on_fly_interval); clearInterval(this.on_fly_interval);
} }
this._super.apply(this, arguments); this._super.apply(this, arguments);
}, },
_onNotification: function(notifications) {
_onNotification: function (notifications) {
var self = this; var self = this;
_.each(notifications, function(notification) {
_.each(notifications, function (notification) {
var channel = notification[0]; var channel = notification[0];
var message = notification[1]; var message = notification[1];
if (channel === self.channel && message) { if (channel === self.channel && message) {

4
kpi_dashboard/static/src/js/dashboard_view.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.DashboardView", function(require) {
odoo.define("kpi_dashboard.DashboardView", function (require) {
"use strict"; "use strict";
var BasicView = require("web.BasicView"); var BasicView = require("web.BasicView");
@ -24,7 +24,7 @@ odoo.define("kpi_dashboard.DashboardView", function(require) {
}), }),
multi_record: false, multi_record: false,
searchable: false, searchable: false,
init: function() {
init: function () {
this._super.apply(this, arguments); this._super.apply(this, arguments);
this.controllerParams.mode = "readonly"; this.controllerParams.mode = "readonly";
this.loadParams.type = "record"; this.loadParams.type = "record";

4
kpi_dashboard/static/src/js/field_widget.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.KpiFieldWidget", function(require) {
odoo.define("kpi_dashboard.KpiFieldWidget", function (require) {
"use strict"; "use strict";
var basic_fields = require("web.basic_fields"); var basic_fields = require("web.basic_fields");
@ -11,7 +11,7 @@ odoo.define("kpi_dashboard.KpiFieldWidget", function(require) {
jsLibs: ["/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.js"], jsLibs: ["/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.js"],
cssLibs: ["/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.css"], cssLibs: ["/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.css"],
className: "o_dashboard_view", className: "o_dashboard_view",
_renderReadonly: function() {
_renderReadonly: function () {
this.$el.html($(qweb.render("dashboard_kpi.dashboard"))); this.$el.html($(qweb.render("dashboard_kpi.dashboard")));
var marginx = 0; var marginx = 0;
var marginy = 0; var marginy = 0;

10
kpi_dashboard/static/src/js/lib/nvd3.js

@ -1,7 +1,7 @@
/* /*
global nv global nv
*/ */
odoo.define("web.nvd3.extensions", function() {
odoo.define("web.nvd3.extensions", function () {
"use strict"; "use strict";
/** /**
@ -16,7 +16,7 @@ odoo.define("web.nvd3.extensions", function() {
// see https://github.com/novus/nvd3/pull/396 for more details // see https://github.com/novus/nvd3/pull/396 for more details
// Adds a resize listener to the window. // Adds a resize listener to the window.
nv.utils.onWindowResize = function(fun) {
nv.utils.onWindowResize = function (fun) {
if (fun === null) return; if (fun === null) return;
window.addEventListener("resize", fun); window.addEventListener("resize", fun);
}; };
@ -25,7 +25,7 @@ odoo.define("web.nvd3.extensions", function() {
nv.utils.windowResize = nv.utils.onWindowResize; nv.utils.windowResize = nv.utils.onWindowResize;
// Removes a resize listener from the window. // Removes a resize listener from the window.
nv.utils.offWindowResize = function(fun) {
nv.utils.offWindowResize = function (fun) {
if (fun === null) return; if (fun === null) return;
window.removeEventListener("resize", fun); window.removeEventListener("resize", fun);
}; };
@ -33,7 +33,7 @@ odoo.define("web.nvd3.extensions", function() {
// Monkey patch nvd3 to prevent crashes when user changes view and nvd3 // Monkey patch nvd3 to prevent crashes when user changes view and nvd3
// tries to remove tooltips after 500 ms... seriously nvd3, what were you // tries to remove tooltips after 500 ms... seriously nvd3, what were you
// thinking? // thinking?
nv.tooltip.cleanup = function() {
nv.tooltip.cleanup = function () {
$(".nvtooltip").remove(); $(".nvtooltip").remove();
}; };
@ -41,7 +41,7 @@ odoo.define("web.nvd3.extensions", function() {
// with a negative `top`; with this patch the highest tooltip's position is // with a negative `top`; with this patch the highest tooltip's position is
// still in the graph // still in the graph
var originalCalcTooltipPosition = nv.tooltip.calcTooltipPosition; var originalCalcTooltipPosition = nv.tooltip.calcTooltipPosition;
nv.tooltip.calcTooltipPosition = function() {
nv.tooltip.calcTooltipPosition = function () {
var container = originalCalcTooltipPosition.apply(this, arguments); var container = originalCalcTooltipPosition.apply(this, arguments);
container.style.top = container.style.top =
container.style.top.split("px")[0] < 0 ? 0 + "px" : container.style.top; container.style.top.split("px")[0] < 0 ? 0 + "px" : container.style.top;

22
kpi_dashboard/static/src/js/widget/abstract_widget.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.AbstractWidget", function(require) {
odoo.define("kpi_dashboard.AbstractWidget", function (require) {
"use strict"; "use strict";
var Widget = require("web.Widget"); var Widget = require("web.Widget");
var field_utils = require("web.field_utils"); var field_utils = require("web.field_utils");
@ -17,7 +17,7 @@ odoo.define("kpi_dashboard.AbstractWidget", function(require) {
"click .o_kpi_dashboard_toggle_button": "_onClickToggleButton", "click .o_kpi_dashboard_toggle_button": "_onClickToggleButton",
"click .direct_action": "_onClickDirectAction", "click .direct_action": "_onClickDirectAction",
}, },
init: function(parent, kpi_values) {
init: function (parent, kpi_values) {
this._super(parent); this._super(parent);
this.col = kpi_values.col; this.col = kpi_values.col;
this.row = kpi_values.row; this.row = kpi_values.row;
@ -37,21 +37,21 @@ odoo.define("kpi_dashboard.AbstractWidget", function(require) {
this.widget_size_y = this.widget_size_y =
this.widget_dimension_y * this.sizey + (this.sizey - 1) * this.margin_y; this.widget_dimension_y * this.sizey + (this.sizey - 1) * this.margin_y;
}, },
willStart: function() {
willStart: function () {
// We need to load the libraries before the start // We need to load the libraries before the start
return $.when(ajax.loadLibs(this), this._super.apply(this, arguments)); return $.when(ajax.loadLibs(this), this._super.apply(this, arguments));
}, },
start: function() {
start: function () {
var self = this; var self = this;
return this._super.apply(this, arguments).then(function() {
return this._super.apply(this, arguments).then(function () {
self._fillWidget(self.values); self._fillWidget(self.values);
}); });
}, },
_onClickToggleButton: function(event) {
_onClickToggleButton: function (event) {
event.preventDefault(); event.preventDefault();
this.$el.toggleClass("o_dropdown_open"); this.$el.toggleClass("o_dropdown_open");
}, },
_fillWidget: function(values) {
_fillWidget: function (values) {
// This function fills the widget values // This function fills the widget values
if (this.$el === undefined) return; if (this.$el === undefined) return;
this.fillWidget(values); this.fillWidget(values);
@ -73,20 +73,20 @@ odoo.define("kpi_dashboard.AbstractWidget", function(require) {
if ($manage && this.showManagePanel(values)) if ($manage && this.showManagePanel(values))
$manage.toggleClass("hidden", false); $manage.toggleClass("hidden", false);
}, },
showManagePanel: function(values) {
showManagePanel: function (values) {
// Hook for extensions // Hook for extensions
return values.actions !== undefined; return values.actions !== undefined;
}, },
fillWidget: function(values) {
fillWidget: function (values) {
// Specific function that will be changed by specific widget // Specific function that will be changed by specific widget
var value = values.value; var value = values.value;
var self = this; var self = this;
_.each(value, function(val, key) {
_.each(value, function (val, key) {
var item = self.$el.find("[data-bind=" + key + "]"); var item = self.$el.find("[data-bind=" + key + "]");
if (item) item.text(val); if (item) item.text(val);
}); });
}, },
_onClickDirectAction: function(event) {
_onClickDirectAction: function (event) {
event.preventDefault(); event.preventDefault();
var $data = $(event.currentTarget).closest("a"); var $data = $(event.currentTarget).closest("a");
var action = this.actions[$($data).data("id")]; var action = this.actions[$($data).data("id")];

2
kpi_dashboard/static/src/js/widget/counter_widget.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.CounterWidget", function(require) {
odoo.define("kpi_dashboard.CounterWidget", function (require) {
"use strict"; "use strict";
var IntegerWidget = require("kpi_dashboard.IntegerWidget"); var IntegerWidget = require("kpi_dashboard.IntegerWidget");

28
kpi_dashboard/static/src/js/widget/graph_widget.js

@ -1,7 +1,7 @@
/* /*
global nv, d3 global nv, d3
*/ */
odoo.define("kpi_dashboard.GraphWidget", function(require) {
odoo.define("kpi_dashboard.GraphWidget", function (require) {
"use strict"; "use strict";
var AbstractWidget = require("kpi_dashboard.AbstractWidget"); var AbstractWidget = require("kpi_dashboard.AbstractWidget");
@ -17,12 +17,12 @@ odoo.define("kpi_dashboard.GraphWidget", function(require) {
"/kpi_dashboard/static/src/js/lib/nvd3.js", "/kpi_dashboard/static/src/js/lib/nvd3.js",
], ],
cssLibs: ["/kpi_dashboard/static/lib/nvd3/nv.d3.css"], cssLibs: ["/kpi_dashboard/static/lib/nvd3/nv.d3.css"],
start: function() {
start: function () {
this._onResize = this._onResize.bind(this); this._onResize = this._onResize.bind(this);
nv.utils.windowResize(this._onResize); nv.utils.windowResize(this._onResize);
return this._super.apply(this, arguments); return this._super.apply(this, arguments);
}, },
destroy: function() {
destroy: function () {
if ("nv" in window && nv.utils && nv.utils.offWindowResize) { if ("nv" in window && nv.utils && nv.utils.offWindowResize) {
// If the widget is destroyed before the lazy loaded libs (nv) are // If the widget is destroyed before the lazy loaded libs (nv) are
// actually loaded (i.e. after the widget has actually started), // actually loaded (i.e. after the widget has actually started),
@ -31,9 +31,9 @@ odoo.define("kpi_dashboard.GraphWidget", function(require) {
} }
this._super.apply(this, arguments); this._super.apply(this, arguments);
}, },
_getChartOptions: function() {
_getChartOptions: function () {
return { return {
x: function(d, u) {
x: function (d, u) {
return u; return u;
}, },
margin: {left: 0, right: 0, top: 5, bottom: 0}, margin: {left: 0, right: 0, top: 5, bottom: 0},
@ -44,11 +44,11 @@ odoo.define("kpi_dashboard.GraphWidget", function(require) {
width: this.widget_size_x - 20, width: this.widget_size_x - 20,
}; };
}, },
_chartConfiguration: function(values) {
_chartConfiguration: function (values) {
this.chart.forceY([0]); this.chart.forceY([0]);
this.chart.xAxis.tickFormat(function(d) {
this.chart.xAxis.tickFormat(function (d) {
var label = ""; var label = "";
_.each(values.value.graphs, function(v) {
_.each(values.value.graphs, function (v) {
if (v.values[d] && v.values[d].x) { if (v.values[d] && v.values[d].x) {
label = v.values[d].x; label = v.values[d].x;
} }
@ -57,7 +57,7 @@ odoo.define("kpi_dashboard.GraphWidget", function(require) {
}); });
this.chart.yAxis.tickFormat(d3.format(",.2f")); this.chart.yAxis.tickFormat(d3.format(",.2f"));
this.chart.tooltip.contentGenerator(function(key) {
this.chart.tooltip.contentGenerator(function (key) {
return qweb.render("GraphCustomTooltip", { return qweb.render("GraphCustomTooltip", {
color: key.point.color, color: key.point.color,
key: key.series[0].title, key: key.series[0].title,
@ -65,7 +65,7 @@ odoo.define("kpi_dashboard.GraphWidget", function(require) {
}); });
}); });
}, },
_addGraph: function(values) {
_addGraph: function (values) {
var data = values.value.graphs; var data = values.value.graphs;
this.$svg.addClass("o_graph_linechart"); this.$svg.addClass("o_graph_linechart");
this.chart = nv.models.lineChart(); this.chart = nv.models.lineChart();
@ -79,23 +79,23 @@ odoo.define("kpi_dashboard.GraphWidget", function(require) {
this.$("svg").css("height", this.widget_size_y - 90); this.$("svg").css("height", this.widget_size_y - 90);
this._customizeChart(); this._customizeChart();
}, },
fillWidget: function(values) {
fillWidget: function (values) {
var self = this; var self = this;
var element = this.$el.find('[data-bind="value"]'); var element = this.$el.find('[data-bind="value"]');
element.empty(); element.empty();
element.css("padding-left", 10).css("padding-right", 10); element.css("padding-left", 10).css("padding-right", 10);
this.chart = null; this.chart = null;
nv.addGraph(function() {
nv.addGraph(function () {
self.$svg = self.$el self.$svg = self.$el
.find('[data-bind="value"]') .find('[data-bind="value"]')
.append("<svg width=" + (self.widget_size_x - 20) + ">"); .append("<svg width=" + (self.widget_size_x - 20) + ">");
self._addGraph(values); self._addGraph(values);
}); });
}, },
_customizeChart: function() {
_customizeChart: function () {
// Hook function // Hook function
}, },
_onResize: function() {
_onResize: function () {
if (this.chart) { if (this.chart) {
this.chart.update(); this.chart.update();
this._customizeChart(); this._customizeChart();

8
kpi_dashboard/static/src/js/widget/integer_widget.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.IntegerWidget", function(require) {
odoo.define("kpi_dashboard.IntegerWidget", function (require) {
"use strict"; "use strict";
var AbstractWidget = require("kpi_dashboard.AbstractWidget"); var AbstractWidget = require("kpi_dashboard.AbstractWidget");
@ -14,12 +14,12 @@ odoo.define("kpi_dashboard.IntegerWidget", function(require) {
[1000000, "M", [3, 1]], [1000000, "M", [3, 1]],
[1000, "K", [3, 1]], [1000, "K", [3, 1]],
], ],
shortNumber: function(num) {
shortNumber: function (num) {
var suffix = ""; var suffix = "";
var shortened = false; var shortened = false;
var digits = this.digits; var digits = this.digits;
var result = num; var result = num;
_.each(this.shortList, function(shortItem) {
_.each(this.shortList, function (shortItem) {
if (!shortened && Math.abs(num) >= shortItem[0]) { if (!shortened && Math.abs(num) >= shortItem[0]) {
shortened = true; shortened = true;
suffix = shortItem[1]; suffix = shortItem[1];
@ -33,7 +33,7 @@ odoo.define("kpi_dashboard.IntegerWidget", function(require) {
}) + suffix }) + suffix
); );
}, },
fillWidget: function(values) {
fillWidget: function (values) {
var widget = this.$el; var widget = this.$el;
var value = values.value.value; var value = values.value.value;
if (value === undefined) { if (value === undefined) {

6
kpi_dashboard/static/src/js/widget/meter_widget.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.MeterWidget", function(require) {
odoo.define("kpi_dashboard.MeterWidget", function (require) {
"use strict"; "use strict";
var AbstractWidget = require("kpi_dashboard.AbstractWidget"); var AbstractWidget = require("kpi_dashboard.AbstractWidget");
@ -7,14 +7,14 @@ odoo.define("kpi_dashboard.MeterWidget", function(require) {
var MeterWidget = AbstractWidget.extend({ var MeterWidget = AbstractWidget.extend({
template: "kpi_dashboard.meter", template: "kpi_dashboard.meter",
jsLibs: ["/kpi_dashboard/static/lib/gauge/GaugeMeter.js"], jsLibs: ["/kpi_dashboard/static/lib/gauge/GaugeMeter.js"],
fillWidget: function(values) {
fillWidget: function (values) {
var input = this.$el.find('[data-bind="value"]'); var input = this.$el.find('[data-bind="value"]');
var options = this._getMeterOptions(values); var options = this._getMeterOptions(values);
var margin = (this.widget_dimension_x - options.size) / 2; var margin = (this.widget_dimension_x - options.size) / 2;
input.gaugeMeter(options); input.gaugeMeter(options);
input.parent().css("padding-left", margin); input.parent().css("padding-left", margin);
}, },
_getMeterOptions: function(values) {
_getMeterOptions: function (values) {
var size = Math.min(this.widget_size_x, this.widget_size_y - 40) - 10; var size = Math.min(this.widget_size_x, this.widget_size_y - 40) - 10;
return { return {
percent: values.value.value, percent: values.value.value,

4
kpi_dashboard/static/src/js/widget/number_widget.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.NumberWidget", function(require) {
odoo.define("kpi_dashboard.NumberWidget", function (require) {
"use strict"; "use strict";
var IntegerWidget = require("kpi_dashboard.IntegerWidget"); var IntegerWidget = require("kpi_dashboard.IntegerWidget");
@ -7,7 +7,7 @@ odoo.define("kpi_dashboard.NumberWidget", function(require) {
var NumberWidget = IntegerWidget.extend({ var NumberWidget = IntegerWidget.extend({
digits: [3, 1], digits: [3, 1],
shortNumber: function(num) {
shortNumber: function (num) {
if (Math.abs(num) < 10) { if (Math.abs(num) < 10) {
return field_utils.format.float(num, false, { return field_utils.format.float(num, false, {
digits: [3, 2], digits: [3, 2],

4
kpi_dashboard/static/src/js/widget/text_widget.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.TextWidget", function(require) {
odoo.define("kpi_dashboard.TextWidget", function (require) {
"use strict"; "use strict";
var AbstractWidget = require("kpi_dashboard.AbstractWidget"); var AbstractWidget = require("kpi_dashboard.AbstractWidget");
@ -6,7 +6,7 @@ odoo.define("kpi_dashboard.TextWidget", function(require) {
var TextWidget = AbstractWidget.extend({ var TextWidget = AbstractWidget.extend({
template: "kpi_dashboard.base_text", template: "kpi_dashboard.base_text",
fillWidget: function() {
fillWidget: function () {
return; return;
}, },
}); });

2
kpi_dashboard/static/src/js/widget_registry.js

@ -1,4 +1,4 @@
odoo.define("kpi_dashboard.widget_registry", function(require) {
odoo.define("kpi_dashboard.widget_registry", function (require) {
"use strict"; "use strict";
var Registry = require("web.Registry"); var Registry = require("web.Registry");

5
kpi_dashboard/static/src/xml/dashboard.xml

@ -29,7 +29,10 @@
class="direct_action" class="direct_action"
t-att-data-id="action_id" t-att-data-id="action_id"
t-att-data-type="action.type" t-att-data-type="action.type"
>Go to <t t-esc="action.name" /></a>
>
Go to
<t t-esc="action.name" />
</a>
</div> </div>
</t> </t>
</t> </t>

6
kpi_dashboard/tests/test_formula.py

@ -45,7 +45,8 @@ result = {{}}
result['value'] = len(model.search([('id', '=', {})])) result['value'] = len(model.search([('id', '=', {})]))
result['previous'] = len(model.search([('id', '!=', {})])) result['previous'] = len(model.search([('id', '!=', {})]))
""".format( """.format(
self.kpi.id, self.kpi.id,
self.kpi.id,
self.kpi.id,
) )
self.kpi.compute() self.kpi.compute()
value = self.kpi.value value = self.kpi.value
@ -65,7 +66,8 @@ result = {{}}
result['value'] = len(model.search([('id', '=', {})])) result['value'] = len(model.search([('id', '=', {})]))
result['previous'] = len(model.search([('id', '!=', {})])) result['previous'] = len(model.search([('id', '!=', {})]))
""".format( """.format(
self.kpi.id, self.kpi.id,
self.kpi.id,
self.kpi.id,
) )
self.kpi.compute() self.kpi.compute()
value = self.kpi.value value = self.kpi.value

2
kpi_dashboard/views/kpi_dashboard.xml

@ -166,7 +166,7 @@
</sheet> </sheet>
<footer> <footer>
<button <button
name="write"
name="store_data"
string="Save" string="Save"
type="object" type="object"
class="oe_highlight" class="oe_highlight"

Loading…
Cancel
Save