diff --git a/kpi_dashboard/demo/demo_dashboard.xml b/kpi_dashboard/demo/demo_dashboard.xml
index 3a31344cc..83aa515ac 100644
--- a/kpi_dashboard/demo/demo_dashboard.xml
+++ b/kpi_dashboard/demo/demo_dashboard.xml
@@ -8,7 +8,6 @@
#020202
30
-
Number 01
$
@@ -18,7 +17,6 @@
result = {"value": 10000,"previous": 12000}
-
Number 02
€
@@ -28,10 +26,11 @@ result = {"value": 10000,"previous": 12000}
result = {"value": 12000,"previous": 10000}
-
-
-
+
Meter 01
€
@@ -41,7 +40,6 @@ result = {"value": 12000,"previous": 10000}
result = {"min": 0, "max": 100, "value": 90}
-
Meter 02
$
@@ -51,10 +49,11 @@ result = {"min": 0, "max": 100, "value": 90}
result = {"min": 0, "max": 100, "value": 40}
-
-
-
+
Graph
code
@@ -84,125 +83,116 @@ result = {"graphs": [
]}
-
-
-
+
Integer counter
code
integer
-
+
result = {"value": self.env.context.get('counter', 990)}
-
Counter
code
counter
-
+
result = {"value": self.env.context.get('counter', 990)}
-
Dashboard title
-
+
1
1
4
#707070
#000000
-
Number 01
-
-
+
+
1
2
4
#47bbb3
#ffffff
-
Number 02
-
-
+
+
1
6
4
#ec663c
#ffffff
-
Meter 01
-
-
+
+
2
2
4
#9c4274
#ffffff
-
Meter 02
-
-
+
+
2
6
4
#12b0c5
#ffffff
-
+1 to Counter
-
+
3
10
1
2
#B41F1F
#EEBF77
-
- {'counter': (context.counter or 990) + 1}
-
- check_if(((context.counter or 990) + 1) % 2, '#ff0000', '#00ff00')
+
+ {'counter': (context.counter or 990) + 1}
+
+ check_if(((context.counter or 990) + 1) % 2, '#ff0000', '#00ff00')
-
Counter
-
-
+
+
3
11
3
#4B0082
#ffffff
-
Integer
-
-
+
+
4
11
3
#ffffff
#4B0082
-
Graph
-
-
+
+
3
2
2
@@ -210,5 +200,4 @@ result = {"value": self.env.context.get('counter', 990)}
#ff9618
#ffffff
-
diff --git a/kpi_dashboard/models/kpi_dashboard.py b/kpi_dashboard/models/kpi_dashboard.py
index 24d423017..c03073ab8 100644
--- a/kpi_dashboard/models/kpi_dashboard.py
+++ b/kpi_dashboard/models/kpi_dashboard.py
@@ -1,7 +1,7 @@
# Copyright 2020 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from odoo import api, fields, models, _
+from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
@@ -17,8 +17,7 @@ class KpiDashboard(models.Model):
)
number_of_columns = fields.Integer(default=5, required=True)
compute_on_fly_refresh = fields.Integer(
- default=0,
- help="Seconds to refresh on fly elements"
+ default=0, help="Seconds to refresh on fly elements"
)
width = fields.Integer(compute="_compute_width")
margin_y = fields.Integer(default=10, required=True)
@@ -34,9 +33,7 @@ class KpiDashboard(models.Model):
if "group_ids" in vals:
for rec in self:
if rec.menu_id:
- rec.menu_id.write(
- {"groups_id": [(6, 0, rec.group_ids.ids)]}
- )
+ rec.menu_id.write({"groups_id": [(6, 0, rec.group_ids.ids)]})
return res
@api.depends("widget_dimension_x", "margin_x", "number_of_columns")
@@ -78,7 +75,7 @@ class KpiDashboard(models.Model):
return {
"parent_id": menu.id or False,
"name": self.name,
- "action": "%s,%s" % (action._name, action.id),
+ "action": "{},{}".format(action._name, action.id),
"groups_id": [(6, 0, self.group_ids.ids)],
}
@@ -106,13 +103,11 @@ class KpiDashboardItem(models.Model):
name = fields.Char(required=True)
kpi_id = fields.Many2one("kpi.kpi")
- dashboard_id = fields.Many2one(
- "kpi.dashboard", required=True, ondelete="cascade"
- )
+ dashboard_id = fields.Many2one("kpi.dashboard", required=True, ondelete="cascade")
column = fields.Integer(required=True, default=1)
row = fields.Integer(required=True, default=1)
- end_row = fields.Integer(store=True, compute='_compute_end_row')
- end_column = fields.Integer(store=True, compute='_compute_end_column')
+ end_row = fields.Integer(store=True, compute="_compute_end_row")
+ end_column = fields.Integer(store=True, compute="_compute_end_column")
size_x = fields.Integer(required=True, default=1)
size_y = fields.Integer(required=True, default=1)
color = fields.Char()
@@ -122,44 +117,43 @@ class KpiDashboardItem(models.Model):
modify_color = fields.Boolean()
modify_color_expression = fields.Char()
- @api.depends('row', 'size_y')
+ @api.depends("row", "size_y")
def _compute_end_row(self):
for r in self:
r.end_row = r.row + r.size_y - 1
- @api.depends('column', 'size_x')
+ @api.depends("column", "size_x")
def _compute_end_column(self):
for r in self:
r.end_column = r.column + r.size_x - 1
- @api.constrains('size_y')
+ @api.constrains("size_y")
def _check_size_y(self):
for rec in self:
if rec.size_y > 10:
- raise ValidationError(_(
- 'Size Y of the widget cannot be bigger than 10'))
+ raise ValidationError(
+ _("Size Y of the widget cannot be bigger than 10")
+ )
def _check_size_domain(self):
return [
- ('dashboard_id', '=', self.dashboard_id.id),
- ('id', '!=', self.id),
- ('row', '<=', self.end_row),
- ('end_row', '>=', self.row),
- ('column', '<=', self.end_column),
- ('end_column', '>=', self.column),
+ ("dashboard_id", "=", self.dashboard_id.id),
+ ("id", "!=", self.id),
+ ("row", "<=", self.end_row),
+ ("end_row", ">=", self.row),
+ ("column", "<=", self.end_column),
+ ("end_column", ">=", self.column),
]
- @api.constrains('end_row', 'end_column', 'row', 'column')
+ @api.constrains("end_row", "end_column", "row", "column")
def _check_size(self):
for r in self:
if self.search(r._check_size_domain(), limit=1):
- raise ValidationError(_(
- 'Widgets cannot be crossed by other widgets'
- ))
+ raise ValidationError(_("Widgets cannot be crossed by other widgets"))
if r.end_column > r.dashboard_id.number_of_columns:
- raise ValidationError(_(
- 'Widget %s is bigger than expected'
- ) % r.display_name)
+ raise ValidationError(
+ _("Widget %s is bigger than expected") % r.display_name
+ )
@api.onchange("kpi_id")
def _onchange_kpi(self):
@@ -181,9 +175,9 @@ class KpiDashboardItem(models.Model):
"modify_color": self.modify_color,
}
if self.modify_context:
- vals['modify_context_expression'] = self.modify_context_expression
+ vals["modify_context_expression"] = self.modify_context_expression
if self.modify_color:
- vals['modify_color_expression'] = self.modify_color_expression
+ vals["modify_color_expression"] = self.modify_color_expression
if self.kpi_id:
vals.update(
{
@@ -195,15 +189,19 @@ class KpiDashboardItem(models.Model):
}
)
if self.kpi_id.compute_on_fly:
- vals.update({
- "value": self.kpi_id._compute_value(),
- "value_last_update": fields.Datetime.now(),
- })
+ 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,
- })
+ 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:
@@ -219,12 +217,13 @@ class KpiDashboardItem(models.Model):
def technical_config(self):
self.ensure_one()
return {
- 'name': self.display_name,
- 'res_model': self._name,
- 'res_id': self.id,
- 'type': 'ir.actions.act_window',
- 'view_mode': 'form',
- 'target': 'new',
- 'view_id': self.env.ref(
- 'kpi_dashboard.kpi_dashboard_item_config_form_view').id,
+ "name": self.display_name,
+ "res_model": self._name,
+ "res_id": self.id,
+ "type": "ir.actions.act_window",
+ "view_mode": "form",
+ "target": "new",
+ "view_id": self.env.ref(
+ "kpi_dashboard.kpi_dashboard_item_config_form_view"
+ ).id,
}
diff --git a/kpi_dashboard/models/kpi_kpi.py b/kpi_dashboard/models/kpi_kpi.py
index a16d613d0..11cb5fd9b 100644
--- a/kpi_dashboard/models/kpi_kpi.py
+++ b/kpi_dashboard/models/kpi_kpi.py
@@ -1,17 +1,20 @@
# Copyright 2020 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-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
-from odoo.tools.float_utils import float_compare
-import re
-import json
import datetime
+import json
+import re
+
from dateutil import relativedelta
+from odoo import _, api, fields, models
+from odoo.exceptions import ValidationError
+from odoo.tools.float_utils import float_compare
+from odoo.tools.safe_eval import safe_eval
+
+from odoo.addons.base.models.ir_cron import _intervalTypes
+
class KpiKpi(models.Model):
_name = "kpi.kpi"
@@ -30,8 +33,13 @@ class KpiKpi(models.Model):
args = fields.Char()
kwargs = fields.Char()
widget = fields.Selection(
- [('integer', 'Integer'), ("number", "Number"), ("meter", "Meter"),
- ('counter', 'Counter'), ("graph", "Graph")],
+ [
+ ("integer", "Integer"),
+ ("number", "Number"),
+ ("meter", "Meter"),
+ ("counter", "Counter"),
+ ("graph", "Graph"),
+ ],
required=True,
default="number",
)
@@ -40,22 +48,21 @@ class KpiKpi(models.Model):
suffix = fields.Char()
action_ids = fields.One2many(
"kpi.kpi.action",
- inverse_name='kpi_id',
- help="Actions that can be opened from the KPI"
+ inverse_name="kpi_id",
+ 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,
+ 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')
+ 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')
+ @api.depends("value", "value_last_update", "compute_on_fly")
def _compute_computed_value(self):
for record in self:
if record.compute_on_fly:
@@ -95,18 +102,19 @@ class KpiKpi(models.Model):
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)
+ 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)
+ 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
@@ -152,9 +160,9 @@ class KpiKpi(models.Model):
if len(message) > 0:
message += _(" or ")
message += forbidden[-1]
- raise ValidationError(_(
- "The code cannot contain the following terms: %s."
- ) % message)
+ raise ValidationError(
+ _("The code cannot contain the following terms: %s.") % message
+ )
results = self._get_code_input_dict()
savepoint = "kpi_formula_%s" % self.id
self.env.cr.execute("savepoint %s" % savepoint)
@@ -164,30 +172,34 @@ class KpiKpi(models.Model):
def show_value(self):
self.ensure_one()
- action = self.env.ref('kpi_dashboard.kpi_kpi_act_window')
+ 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')],
- })
+ 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'
- _description = 'KPI action'
+ _name = "kpi.kpi.action"
+ _description = "KPI action"
- kpi_id = fields.Many2one('kpi.kpi', required=True, ondelete='cascade')
+ kpi_id = fields.Many2one("kpi.kpi", required=True, ondelete="cascade")
action = fields.Reference(
- selection=[('ir.actions.report', 'ir.actions.report'),
- ('ir.actions.act_window', 'ir.actions.act_window'),
- ('ir.actions.act_url', 'ir.actions.act_url'),
- ('ir.actions.server', 'ir.actions.server'),
- ('ir.actions.client', 'ir.actions.client')],
+ selection=[
+ ("ir.actions.report", "ir.actions.report"),
+ ("ir.actions.act_window", "ir.actions.act_window"),
+ ("ir.actions.act_url", "ir.actions.act_url"),
+ ("ir.actions.server", "ir.actions.server"),
+ ("ir.actions.client", "ir.actions.client"),
+ ],
required=True,
)
context = fields.Char()
@@ -196,43 +208,45 @@ class KpiKpiAction(models.Model):
result = {}
for r in self:
result[r.id] = {
- 'id': r.action.id,
- 'type': r.action._name,
- 'name': r.action.name,
- 'context': safe_eval(r.context or '{}')
+ "id": r.action.id,
+ "type": r.action._name,
+ "name": r.action.name,
+ "context": safe_eval(r.context or "{}"),
}
return result
class KpiKpiHistory(models.Model):
- _name = 'kpi.kpi.history'
- _description = 'KPI history'
- _order = 'create_date DESC'
+ _name = "kpi.kpi.history"
+ _description = "KPI history"
+ _order = "create_date DESC"
kpi_id = fields.Many2one(
- 'kpi.kpi', required=True, ondelete='cascade', readonly=True
+ "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')
+ 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)
+ selection=lambda self: self.env["kpi.kpi"]._fields["widget"].selection,
+ required=True,
+ )
- @api.depends('value')
+ @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')
+ 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')],
- })
+ result.update(
+ {
+ "res_id": self.id,
+ "target": "new",
+ "view_mode": "form",
+ "views": [(self.env.context.get("form_id"), "form")],
+ }
+ )
return result
diff --git a/kpi_dashboard/security/security.xml b/kpi_dashboard/security/security.xml
index fb16b0f7e..dd87e7c2d 100755
--- a/kpi_dashboard/security/security.xml
+++ b/kpi_dashboard/security/security.xml
@@ -1,22 +1,24 @@
-
+
Manage KPI Dashboards
-
-
+
+
KPI Dashboard: User
-
- ['|', ('group_ids', '=', False), ('group_ids', 'in', user.groups_id.ids)]
-
+
+ ['|', ('group_ids', '=', False), ('group_ids', 'in', user.groups_id.ids)]
+
KPI Dashboard: All
-
+
[(1, '=', 1)]
-
+
diff --git a/kpi_dashboard/static/src/js/dashboard_controller.js b/kpi_dashboard/static/src/js/dashboard_controller.js
index 97db1765d..7910f82c1 100644
--- a/kpi_dashboard/static/src/js/dashboard_controller.js
+++ b/kpi_dashboard/static/src/js/dashboard_controller.js
@@ -1,150 +1,159 @@
-odoo.define('kpi_dashboard.DashboardController', function (require) {
+odoo.define("kpi_dashboard.DashboardController", function(require) {
"use strict";
- var BasicController = require('web.BasicController');
- var core = require('web.core');
+ var BasicController = require("web.BasicController");
+ var core = require("web.core");
var qweb = core.qweb;
var _t = core._t;
var DashboardController = BasicController.extend({
- init: function () {
+ init: function() {
this._super.apply(this, arguments);
this.dashboard_context = {};
- this.dashboard_color_data = []
+ this.dashboard_color_data = [];
},
custom_events: _.extend({}, BasicController.prototype.custom_events, {
- addDashboard: '_addDashboard',
- refresh_on_fly: '_refreshOnFly',
- modify_context: '_modifyContext',
- add_modify_color: '_addModifyColor',
- refresh_colors: '_refreshColors',
+ addDashboard: "_addDashboard",
+ refresh_on_fly: "_refreshOnFly",
+ modify_context: "_modifyContext",
+ add_modify_color: "_addModifyColor",
+ refresh_colors: "_refreshColors",
}),
- _refreshOnFly: function (event) {
+ _refreshOnFly: function(event) {
var self = this;
this._rpc({
model: this.modelName,
- method: 'read_dashboard_on_fly',
+ method: "read_dashboard_on_fly",
args: [[this.renderer.state.res_id]],
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
- self.renderer._onNotification([[
- "kpi_dashboard_" + self.renderer.state.res_id,
- item
- ]])
+ self.renderer._onNotification([
+ ["kpi_dashboard_" + self.renderer.state.res_id, item],
+ ]);
});
});
},
- renderPager: function ($node, options) {
+ renderPager: function($node, options) {
options = _.extend({}, options, {
validate: this.canBeDiscarded.bind(this),
});
this._super($node, options);
},
- _pushState: function (state) {
+ _pushState: function(state) {
state = state || {};
var env = this.model.get(this.handle, {env: true});
state.id = env.currentId;
this._super(state);
},
- _addDashboard: function () {
+ _addDashboard: function() {
var self = this;
var action = self.initialState.specialData.action_id;
var name = self.initialState.specialData.name;
- if (! action) {
+ if (!action) {
self.do_warn(_t("First you must create the Menu"));
}
- return self._rpc({
- route: '/board/add_to_dashboard',
- params: {
- action_id: action,
- context_to_save: {'res_id': self.initialState.res_id},
- domain: [('id', '=', self.initialState.res_id)],
- view_mode: 'dashboard',
- name: name,
- },
- })
- .then(function (r) {
- if (r) {
- self.do_notify(
- _.str.sprintf(_t("'%s' added to dashboard"), name),
- _t('Please refresh your browser for the changes to take effect.')
- );
- } else {
- self.do_warn(_t("Could not add KPI dashboard to dashboard"));
- }
- });
+ return self
+ ._rpc({
+ route: "/board/add_to_dashboard",
+ params: {
+ action_id: action,
+ context_to_save: {res_id: self.initialState.res_id},
+ domain: [("id", "=", self.initialState.res_id)],
+ view_mode: "dashboard",
+ name: name,
+ },
+ })
+ .then(function(r) {
+ if (r) {
+ self.do_notify(
+ _.str.sprintf(_t("'%s' added to dashboard"), name),
+ _t(
+ "Please refresh your browser for the changes to take effect."
+ )
+ );
+ } else {
+ self.do_warn(_t("Could not add KPI dashboard to dashboard"));
+ }
+ });
},
- _updateButtons: function () {
+ _updateButtons: function() {
// HOOK Function
this.$buttons.on(
- 'click', '.o_dashboard_button_add',
- this._addDashboard.bind(this));
+ "click",
+ ".o_dashboard_button_add",
+ this._addDashboard.bind(this)
+ );
},
- renderButtons: function ($node) {
- if (! $node) {
+ renderButtons: function($node) {
+ if (!$node) {
return;
}
- this.$buttons = $('
');
- this.$buttons.append(qweb.render(
- "kpi_dashboard.buttons", {widget: this}));
+ this.$buttons = $("");
+ this.$buttons.append(qweb.render("kpi_dashboard.buttons", {widget: this}));
this._updateButtons();
this.$buttons.appendTo($node);
},
- _getContext: function () {
+ _getContext: function() {
return _.extend(
{},
this.model.get(this.handle, {raw: true}).getContext(),
{bin_size: true},
- this.dashboard_context,
- )
+ this.dashboard_context
+ );
},
- _modifyContext: function (event) {
+ _modifyContext: function(event) {
var ctx = this._getContext();
this.dashboard_context = _.extend(
this.dashboard_context,
- py.eval(event.data.context, {context: _.extend(
- ctx,
- {__getattr__: function() {return false}}
- // We need to add this in order to allow to use undefined
- // context items
- )}),
+ py.eval(event.data.context, {
+ context: _.extend(
+ ctx,
+ {
+ __getattr__: function() {
+ return false;
+ },
+ }
+ // We need to add this in order to allow to use undefined
+ // context items
+ ),
+ })
);
this._refreshOnFly(event);
this._refreshColors();
},
- _addModifyColor: function (event) {
+ _addModifyColor: function(event) {
this.dashboard_color_data.push([
event.data.element_id,
event.data.expression,
]);
},
- _refreshColors: function () {
+ _refreshColors: function() {
var self = this;
var ctx = this._getContext();
- _.each(this.dashboard_color_data, function (data) {
+ _.each(this.dashboard_color_data, function(data) {
var color = py.eval(data[1], {
context: _.extend(ctx, {
- __getattr__: function() {return false},
-
+ __getattr__: function() {
+ return false;
+ },
}),
check_if: function(args) {
if (args[0].toJSON()) {
return args[1];
}
return args[2];
- }
+ },
});
- var $element = self.renderer.$el.find('#' + data[0]);
- $element.css('background-color', color);
+ var $element = self.renderer.$el.find("#" + data[0]);
+ $element.css("background-color", color);
});
},
});
return DashboardController;
-
});
diff --git a/kpi_dashboard/static/src/js/dashboard_model.js b/kpi_dashboard/static/src/js/dashboard_model.js
index ddf7425e3..93f0eb5c7 100644
--- a/kpi_dashboard/static/src/js/dashboard_model.js
+++ b/kpi_dashboard/static/src/js/dashboard_model.js
@@ -1,23 +1,21 @@
-odoo.define('kpi_dashboard.DashboardModel', function (require) {
+odoo.define("kpi_dashboard.DashboardModel", function(require) {
"use strict";
- var BasicModel = require('web.BasicModel');
+ var BasicModel = require("web.BasicModel");
var DashboardModel = BasicModel.extend({
- _fetchRecord: function (record, options) {
+ _fetchRecord: function(record, options) {
return this._rpc({
model: record.model,
- method: 'read_dashboard',
+ method: "read_dashboard",
args: [[record.res_id]],
context: _.extend({}, record.getContext(), {bin_size: true}),
- })
- .then(function (result) {
+ }).then(function(result) {
record.specialData = result;
- return result
- })
- }
+ return result;
+ });
+ },
});
return DashboardModel;
-
});
diff --git a/kpi_dashboard/static/src/js/dashboard_renderer.js b/kpi_dashboard/static/src/js/dashboard_renderer.js
index 6bc38c492..0caa85fc1 100644
--- a/kpi_dashboard/static/src/js/dashboard_renderer.js
+++ b/kpi_dashboard/static/src/js/dashboard_renderer.js
@@ -1,99 +1,98 @@
-odoo.define('kpi_dashboard.DashboardRenderer', function (require) {
+odoo.define("kpi_dashboard.DashboardRenderer", function(require) {
"use strict";
- var BasicRenderer = require('web.BasicRenderer');
- var core = require('web.core');
- var registry = require('kpi_dashboard.widget_registry');
- var BusService = require('bus.BusService');
+ var BasicRenderer = require("web.BasicRenderer");
+ var core = require("web.core");
+ var registry = require("kpi_dashboard.widget_registry");
+ var BusService = require("bus.BusService");
var qweb = core.qweb;
- var DashboardRenderer= BasicRenderer.extend({
+ var DashboardRenderer = BasicRenderer.extend({
className: "o_dashboard_view",
- _getDashboardWidget: function (kpi) {
- var Widget = registry.getAny([
- kpi.widget, 'abstract',
- ]);
+ _getDashboardWidget: function(kpi) {
+ var Widget = registry.getAny([kpi.widget, "abstract"]);
var widget = new Widget(this, kpi);
return widget;
},
- _onClickModifyContext: function (modify_context_expression, event) {
- this.trigger_up('modify_context', {
+ _onClickModifyContext: function(modify_context_expression, event) {
+ this.trigger_up("modify_context", {
context: modify_context_expression,
event: event,
- })
+ });
},
- _renderView: function () {
- this.$el.html($(qweb.render('dashboard_kpi.dashboard')));
- this.$el.css(
- 'background-color', this.state.specialData.background_color);
- this.$el.find('.gridster')
- .css('width', this.state.specialData.width);
- this.$grid = this.$el.find('.gridster ul');
+ _renderView: function() {
+ this.$el.html($(qweb.render("dashboard_kpi.dashboard")));
+ this.$el.css("background-color", this.state.specialData.background_color);
+ this.$el.find(".gridster").css("width", this.state.specialData.width);
+ this.$grid = this.$el.find(".gridster ul");
var self = this;
this.kpi_widget = {};
- _.each(this.state.specialData.item_ids, function (kpi) {
- var element = $(qweb.render(
- 'kpi_dashboard.kpi', {widget: kpi}));
- element.css('background-color', kpi.color);
- element.css('color', kpi.font_color);
- element.attr('id', _.uniqueId('kpi_'));
+ _.each(this.state.specialData.item_ids, function(kpi) {
+ var element = $(qweb.render("kpi_dashboard.kpi", {widget: kpi}));
+ element.css("background-color", kpi.color);
+ element.css("color", kpi.font_color);
+ element.attr("id", _.uniqueId("kpi_"));
self.$grid.append(element);
if (kpi.modify_color) {
self.trigger_up("add_modify_color", {
element_id: element.attr("id"),
expression: kpi.modify_color_expression,
- })
+ });
}
if (kpi.modify_context) {
- element.on("click", self._onClickModifyContext.bind(
- self, kpi.modify_context_expression));
- element.css('cursor', 'pointer');
+ element.on(
+ "click",
+ self._onClickModifyContext.bind(
+ self,
+ kpi.modify_context_expression
+ )
+ );
+ element.css("cursor", "pointer");
// We want to set it show as clickable
}
self.kpi_widget[kpi.id] = self._getDashboardWidget(kpi);
self.kpi_widget[kpi.id].appendTo(element);
});
- this.$grid.gridster({
- widget_margins: [
- this.state.specialData.margin_x,
- this.state.specialData.margin_y,
- ],
- widget_base_dimensions: [
- this.state.specialData.widget_dimension_x,
- this.state.specialData.widget_dimension_y,
- ],
- cols: this.state.specialData.max_cols,
- }).data('gridster').disable();
- this.channel = 'kpi_dashboard_' + this.state.res_id;
- this.call(
- 'bus_service', 'addChannel', this.channel);
- this.call('bus_service', 'startPolling');
- this.call(
- 'bus_service', 'onNotification',
- this, this._onNotification
- );
+ this.$grid
+ .gridster({
+ widget_margins: [
+ this.state.specialData.margin_x,
+ this.state.specialData.margin_y,
+ ],
+ widget_base_dimensions: [
+ this.state.specialData.widget_dimension_x,
+ this.state.specialData.widget_dimension_y,
+ ],
+ cols: this.state.specialData.max_cols,
+ })
+ .data("gridster")
+ .disable();
+ this.channel = "kpi_dashboard_" + this.state.res_id;
+ this.call("bus_service", "addChannel", this.channel);
+ this.call("bus_service", "startPolling");
+ this.call("bus_service", "onNotification", this, this._onNotification);
if (this.state.specialData.compute_on_fly_refresh > 0) {
// Setting the refresh interval
- this.on_fly_interval = setInterval(function () {
- self.trigger_up('refresh_on_fly');
- }, this.state.specialData.compute_on_fly_refresh *1000);
- };
- this.trigger_up('refresh_colors');
- this.trigger_up('refresh_on_fly');
+ this.on_fly_interval = setInterval(function() {
+ self.trigger_up("refresh_on_fly");
+ }, this.state.specialData.compute_on_fly_refresh * 1000);
+ }
+ this.trigger_up("refresh_colors");
+ this.trigger_up("refresh_on_fly");
// We need to refreshs data in order compute with the current
// context
return $.when();
},
- on_detach_callback: function () {
+ on_detach_callback: function() {
// We want to clear the refresh interval once we exit the view
if (this.on_fly_interval) {
- clearInterval(this.on_fly_interval)
+ clearInterval(this.on_fly_interval);
}
this._super.apply(this, arguments);
},
- _onNotification: function (notifications) {
+ _onNotification: function(notifications) {
var self = this;
- _.each(notifications, function (notification) {
+ _.each(notifications, function(notification) {
var channel = notification[0];
var message = notification[1];
if (channel === self.channel && message) {
diff --git a/kpi_dashboard/static/src/js/dashboard_view.js b/kpi_dashboard/static/src/js/dashboard_view.js
index b31df5cbb..e83dc991f 100644
--- a/kpi_dashboard/static/src/js/dashboard_view.js
+++ b/kpi_dashboard/static/src/js/dashboard_view.js
@@ -1,26 +1,22 @@
-odoo.define('kpi_dashboard.DashboardView', function (require) {
+odoo.define("kpi_dashboard.DashboardView", function(require) {
"use strict";
- var BasicView = require('web.BasicView');
- var DashboardController = require('kpi_dashboard.DashboardController');
- var DashboardModel = require('kpi_dashboard.DashboardModel');
- var DashboardRenderer = require('kpi_dashboard.DashboardRenderer');
- var view_registry = require('web.view_registry');
- var core = require('web.core');
+ var BasicView = require("web.BasicView");
+ var DashboardController = require("kpi_dashboard.DashboardController");
+ var DashboardModel = require("kpi_dashboard.DashboardModel");
+ var DashboardRenderer = require("kpi_dashboard.DashboardRenderer");
+ var view_registry = require("web.view_registry");
+ var core = require("web.core");
var _lt = core._lt;
var DashboardView = BasicView.extend({
- jsLibs: [
- '/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.js',
- ],
- cssLibs: [
- '/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.css',
- ],
+ jsLibs: ["/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.js"],
+ cssLibs: ["/kpi_dashboard/static/lib/gridster/jquery.dsmorse-gridster.min.css"],
accesskey: "d",
display_name: _lt("Dashboard"),
- icon: 'fa-tachometer',
- viewType: 'dashboard',
+ icon: "fa-tachometer",
+ viewType: "dashboard",
config: _.extend({}, BasicView.prototype.config, {
Controller: DashboardController,
Renderer: DashboardRenderer,
@@ -28,17 +24,17 @@ odoo.define('kpi_dashboard.DashboardView', function (require) {
}),
multi_record: false,
searchable: false,
- init: function () {
+ init: function() {
this._super.apply(this, arguments);
- this.controllerParams.mode = 'readonly';
- this.loadParams.type = 'record';
- if (! this.loadParams.res_id && this.loadParams.context.res_id) {
+ this.controllerParams.mode = "readonly";
+ this.loadParams.type = "record";
+ if (!this.loadParams.res_id && this.loadParams.context.res_id) {
this.loadParams.res_id = this.loadParams.context.res_id;
}
},
});
- view_registry.add('dashboard', DashboardView);
+ view_registry.add("dashboard", DashboardView);
return DashboardView;
});
diff --git a/kpi_dashboard/static/src/js/field_widget.js b/kpi_dashboard/static/src/js/field_widget.js
index 2a25003ec..3c9a61408 100644
--- a/kpi_dashboard/static/src/js/field_widget.js
+++ b/kpi_dashboard/static/src/js/field_widget.js
@@ -1,28 +1,24 @@
-odoo.define('kpi_dashboard.KpiFieldWidget', function(require) {
+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 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 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')));
+ 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');
+ this.$el.find(".gridster").css("width", widgety);
+ this.$grid = this.$el.find(".gridster ul");
var widgetVals = {
value: this.value,
col: 1,
@@ -30,10 +26,11 @@ odoo.define('kpi_dashboard.KpiFieldWidget', function(require) {
sizex: 1,
sizey: 1,
name: this.recordData[this.nodeOptions.name],
- value_last_update: this.recordData[this.nodeOptions.date]
- }
+ value_last_update: this.recordData[this.nodeOptions.date],
+ };
var Widget = registry.getAny([
- this.recordData[this.nodeOptions.widget], 'abstract',
+ this.recordData[this.nodeOptions.widget],
+ "abstract",
]);
this.state = {
specialData: {
@@ -41,28 +38,24 @@ odoo.define('kpi_dashboard.KpiFieldWidget', function(require) {
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');
+ 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();
+ 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);
+ field_registry.add("kpi", KpiFieldWidget);
return KpiFieldWidget;
});
diff --git a/kpi_dashboard/static/src/js/widget/abstract_widget.js b/kpi_dashboard/static/src/js/widget/abstract_widget.js
index 470054f31..0d1ffb4fa 100644
--- a/kpi_dashboard/static/src/js/widget/abstract_widget.js
+++ b/kpi_dashboard/static/src/js/widget/abstract_widget.js
@@ -1,20 +1,20 @@
-odoo.define('kpi_dashboard.AbstractWidget', function (require) {
+odoo.define("kpi_dashboard.AbstractWidget", function(require) {
"use strict";
- var Widget = require('web.Widget');
- var field_utils = require('web.field_utils');
- var time = require('web.time');
- var ajax = require('web.ajax');
- var registry = require('kpi_dashboard.widget_registry');
+ var Widget = require("web.Widget");
+ var field_utils = require("web.field_utils");
+ var time = require("web.time");
+ var ajax = require("web.ajax");
+ var registry = require("kpi_dashboard.widget_registry");
var AbstractWidget = Widget.extend({
- template: 'kpi_dashboard.base_widget', // Template used by the widget
+ template: "kpi_dashboard.base_widget", // Template used by the widget
cssLibs: [], // Specific css of the widget
jsLibs: [], // Specific Javascript libraries of the widget
events: {
- 'click .o_kpi_dashboard_toggle_button': '_onClickToggleButton',
- 'click .direct_action': '_onClickDirectAction',
+ "click .o_kpi_dashboard_toggle_button": "_onClickToggleButton",
+ "click .direct_action": "_onClickDirectAction",
},
- init: function (parent, kpi_values) {
+ init: function(parent, kpi_values) {
this._super(parent);
this.col = kpi_values.col;
this.row = kpi_values.row;
@@ -29,66 +29,70 @@ odoo.define('kpi_dashboard.AbstractWidget', function (require) {
this.prefix = kpi_values.prefix;
this.suffix = kpi_values.suffix;
this.actions = kpi_values.actions;
- this.widget_size_x = this.widget_dimension_x * this.sizex +
- (this.sizex - 1) * this.margin_x;
- this.widget_size_y = this.widget_dimension_y * this.sizey +
- (this.sizey - 1) * this.margin_y;
+ this.widget_size_x =
+ this.widget_dimension_x * this.sizex + (this.sizex - 1) * this.margin_x;
+ this.widget_size_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
return $.when(ajax.loadLibs(this), this._super.apply(this, arguments));
},
- start: function () {
+ start: function() {
var self = this;
- return this._super.apply(this, arguments).then(function () {
+ return this._super.apply(this, arguments).then(function() {
self._fillWidget(self.values);
});
},
- _onClickToggleButton: function (event) {
+ _onClickToggleButton: function(event) {
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
- if (this.$el === undefined)
- return;
+ if (this.$el === undefined) return;
this.fillWidget(values);
var item = this.$el.find('[data-bind="value_last_update_display"]');
- if (item && ! values.compute_on_fly && values.value_last_update !== undefined) {
+ if (
+ item &&
+ !values.compute_on_fly &&
+ values.value_last_update !== undefined
+ ) {
var value = field_utils.parse.datetime(values.value_last_update);
- item.text(value.clone().add(
- this.getSession().getTZOffset(value), 'minutes').format(
- time.getLangDatetimeFormat()
- ));
+ item.text(
+ value
+ .clone()
+ .add(this.getSession().getTZOffset(value), "minutes")
+ .format(time.getLangDatetimeFormat())
+ );
}
- var $manage = this.$el.find('.o_kpi_dashboard_manage');
+ var $manage = this.$el.find(".o_kpi_dashboard_manage");
if ($manage && this.showManagePanel(values))
- $manage.toggleClass('hidden', false);
+ $manage.toggleClass("hidden", false);
},
- showManagePanel: function (values) {
+ showManagePanel: function(values) {
// 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
var value = values.value;
var self = this;
- _.each(value, function (val, key) {
- var item = self.$el.find('[data-bind=' + key + ']')
- if (item)
- item.text(val);
- })
+ _.each(value, function(val, key) {
+ var item = self.$el.find("[data-bind=" + key + "]");
+ if (item) item.text(val);
+ });
},
_onClickDirectAction: function(event) {
event.preventDefault();
- var $data = $(event.currentTarget).closest('a');
- var action = this.actions[$($data).data('id')];
+ var $data = $(event.currentTarget).closest("a");
+ var action = this.actions[$($data).data("id")];
return this.do_action(action.id, {
- additional_context: action.context
+ additional_context: action.context,
});
- }
+ },
});
- registry.add('abstract', AbstractWidget);
+ registry.add("abstract", AbstractWidget);
return AbstractWidget;
});
diff --git a/kpi_dashboard/static/src/js/widget/counter_widget.js b/kpi_dashboard/static/src/js/widget/counter_widget.js
index 6005298f2..019afd671 100644
--- a/kpi_dashboard/static/src/js/widget/counter_widget.js
+++ b/kpi_dashboard/static/src/js/widget/counter_widget.js
@@ -1,14 +1,14 @@
-odoo.define('kpi_dashboard.CounterWidget', function (require) {
+odoo.define("kpi_dashboard.CounterWidget", function(require) {
"use strict";
- var IntegerWidget = require('kpi_dashboard.IntegerWidget');
- var registry = require('kpi_dashboard.widget_registry');
- var field_utils = require('web.field_utils');
+ var IntegerWidget = require("kpi_dashboard.IntegerWidget");
+ var registry = require("kpi_dashboard.widget_registry");
+ var field_utils = require("web.field_utils");
var CounterWidget = IntegerWidget.extend({
shortList: [],
});
- registry.add('counter', CounterWidget);
+ registry.add("counter", CounterWidget);
return CounterWidget;
});
diff --git a/kpi_dashboard/static/src/js/widget/graph_widget.js b/kpi_dashboard/static/src/js/widget/graph_widget.js
index 94d606882..d3e492268 100644
--- a/kpi_dashboard/static/src/js/widget/graph_widget.js
+++ b/kpi_dashboard/static/src/js/widget/graph_widget.js
@@ -1,40 +1,39 @@
-odoo.define('kpi_dashboard.GraphWidget', function (require) {
+odoo.define("kpi_dashboard.GraphWidget", function(require) {
"use strict";
- var AbstractWidget = require('kpi_dashboard.AbstractWidget');
- var registry = require('kpi_dashboard.widget_registry');
- var core = require('web.core');
+ var AbstractWidget = require("kpi_dashboard.AbstractWidget");
+ var registry = require("kpi_dashboard.widget_registry");
+ var core = require("web.core");
var qweb = core.qweb;
-
var GraphWidget = AbstractWidget.extend({
- template: 'kpi_dashboard.graph',
+ template: "kpi_dashboard.graph",
jsLibs: [
- '/web/static/lib/nvd3/d3.v3.js',
- '/web/static/lib/nvd3/nv.d3.js',
- '/web/static/src/js/libs/nvd3.js',
+ "/web/static/lib/nvd3/d3.v3.js",
+ "/web/static/lib/nvd3/nv.d3.js",
+ "/web/static/src/js/libs/nvd3.js",
],
- cssLibs: [
- '/web/static/lib/nvd3/nv.d3.css',
- ],
- start: function () {
+ cssLibs: ["/web/static/lib/nvd3/nv.d3.css"],
+ start: function() {
this._onResize = this._onResize.bind(this);
nv.utils.windowResize(this._onResize);
return this._super.apply(this, arguments);
},
- destroy: function () {
- if ('nv' in window && nv.utils && nv.utils.offWindowResize) {
- // if the widget is destroyed before the lazy loaded libs (nv) are
+ destroy: function() {
+ if ("nv" in window && nv.utils && nv.utils.offWindowResize) {
+ // If the widget is destroyed before the lazy loaded libs (nv) are
// actually loaded (i.e. after the widget has actually started),
// nv is undefined, but the handler isn't bound yet anyway
nv.utils.offWindowResize(this._onResize);
}
this._super.apply(this, arguments);
},
- _getChartOptions: function (values) {
+ _getChartOptions: function(values) {
return {
- x: function (d, u) { return u; },
- margin: {'left': 0, 'right': 0, 'top': 5, 'bottom': 0},
+ x: function(d, u) {
+ return u;
+ },
+ margin: {left: 0, right: 0, top: 5, bottom: 0},
showYAxis: false,
showXAxis: false,
showLegend: false,
@@ -42,60 +41,58 @@ odoo.define('kpi_dashboard.GraphWidget', function (require) {
width: this.widget_size_x - 20,
};
},
- _chartConfiguration: function (values) {
-
+ _chartConfiguration: function(values) {
this.chart.forceY([0]);
- this.chart.xAxis.tickFormat(function (d) {
- var label = '';
- _.each(values.value.graphs, function (v) {
+ this.chart.xAxis.tickFormat(function(d) {
+ var label = "";
+ _.each(values.value.graphs, function(v) {
if (v.values[d] && v.values[d].x) {
label = v.values[d].x;
}
});
return label;
});
- this.chart.yAxis.tickFormat(d3.format(',.2f'));
+ this.chart.yAxis.tickFormat(d3.format(",.2f"));
- this.chart.tooltip.contentGenerator(function (key) {
- return qweb.render('GraphCustomTooltip', {
- 'color': key.point.color,
- 'key': key.series[0].title,
- 'value': d3.format(',.2f')(key.point.y)
+ this.chart.tooltip.contentGenerator(function(key) {
+ return qweb.render("GraphCustomTooltip", {
+ color: key.point.color,
+ key: key.series[0].title,
+ value: d3.format(",.2f")(key.point.y),
});
});
},
- _addGraph: function (values) {
+ _addGraph: function(values) {
var data = values.value.graphs;
- this.$svg.addClass('o_graph_linechart');
+ this.$svg.addClass("o_graph_linechart");
this.chart = nv.models.lineChart();
- this.chart.options(
- this._getChartOptions(values)
- );
+ this.chart.options(this._getChartOptions(values));
this._chartConfiguration(values);
- d3.select(this.$('svg')[0])
+ d3.select(this.$("svg")[0])
.datum(data)
- .transition().duration(600)
+ .transition()
+ .duration(600)
.call(this.chart);
- this.$('svg').css('height', this.widget_size_y - 90);
+ this.$("svg").css("height", this.widget_size_y - 90);
this._customizeChart();
},
- fillWidget: function (values) {
+ fillWidget: function(values) {
var self = this;
var element = this.$el.find('[data-bind="value"]');
element.empty();
- element.css('padding-left', 10).css('padding-right', 10);
+ element.css("padding-left", 10).css("padding-right", 10);
this.chart = null;
- nv.addGraph(function () {
- self.$svg = self.$el.find(
- '[data-bind="value"]'
- ).append('