Browse Source

[MIG] kpi_dashboard: migration to 13.0

myc-14.0-py3o
Enric Tobella 4 years ago
parent
commit
4b3f01e27b
  1. 4
      kpi_dashboard/__manifest__.py
  2. 3
      kpi_dashboard/models/kpi_kpi.py
  3. 0
      kpi_dashboard/security/security.xml
  4. 9503
      kpi_dashboard/static/lib/nvd3/d3.v3.js
  5. 427
      kpi_dashboard/static/lib/nvd3/nv.d3.css
  6. 5985
      kpi_dashboard/static/lib/nvd3/nv.d3.js
  7. 7
      kpi_dashboard/static/src/js/dashboard_controller.js
  8. 2
      kpi_dashboard/static/src/js/dashboard_model.js
  9. 1
      kpi_dashboard/static/src/js/dashboard_renderer.js
  10. 50
      kpi_dashboard/static/src/js/lib/nvd3.js
  11. 9
      kpi_dashboard/static/src/js/widget/abstract_widget.js
  12. 1
      kpi_dashboard/static/src/js/widget/counter_widget.js
  13. 13
      kpi_dashboard/static/src/js/widget/graph_widget.js
  14. 5
      kpi_dashboard/static/src/js/widget/integer_widget.js
  15. 4
      kpi_dashboard/static/src/js/widget/meter_widget.js
  16. 8
      kpi_dashboard/tests/test_formula.py
  17. 4
      kpi_dashboard/tests/test_kpi_dashboard.py
  18. 3
      kpi_dashboard/wizards/kpi_dashboard_menu.py

4
kpi_dashboard/__manifest__.py

@ -5,11 +5,11 @@
"name": "Kpi Dashboard", "name": "Kpi Dashboard",
"summary": """ "summary": """
Create Dashboards using kpis""", Create Dashboards using kpis""",
"version": "12.0.1.3.0",
"version": "13.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",
"depends": ["bus", "board", "base_sparse_field", "web_widget_color"],
"depends": ["bus", "board", "base_sparse_field"],
"qweb": ["static/src/xml/dashboard.xml"], "qweb": ["static/src/xml/dashboard.xml"],
"data": [ "data": [
"wizards/kpi_dashboard_menu.xml", "wizards/kpi_dashboard_menu.xml",

3
kpi_dashboard/models/kpi_kpi.py

@ -134,7 +134,6 @@ class KpiKpi(models.Model):
self.ensure_one() self.ensure_one()
self.cron_id = self.env["ir.cron"].create(self._cron_vals()) self.cron_id = self.env["ir.cron"].create(self._cron_vals())
@api.multi
def write(self, vals): def write(self, vals):
if "value" in vals: if "value" in vals:
vals["value_last_update"] = fields.Datetime.now() vals["value_last_update"] = fields.Datetime.now()
@ -165,8 +164,10 @@ class KpiKpi(models.Model):
) )
results = self._get_code_input_dict() results = self._get_code_input_dict()
savepoint = "kpi_formula_%s" % self.id savepoint = "kpi_formula_%s" % self.id
# pylint: disable=E8103
self.env.cr.execute("savepoint %s" % savepoint) self.env.cr.execute("savepoint %s" % savepoint)
safe_eval(self.code or "", results, mode="exec", nocopy=True) safe_eval(self.code or "", results, mode="exec", nocopy=True)
# pylint: disable=E8103
self.env.cr.execute("rollback to %s" % savepoint) self.env.cr.execute("rollback to %s" % savepoint)
return results.get("result", {}) return results.get("result", {})

0
kpi_dashboard/security/security.xml

9503
kpi_dashboard/static/lib/nvd3/d3.v3.js
File diff suppressed because it is too large
View File

427
kpi_dashboard/static/lib/nvd3/nv.d3.css

@ -0,0 +1,427 @@
/* nvd3 version 1.8.2-dev (https://github.com/novus/nvd3) 2016-02-08 */
.nvd3 .nv-axis {
pointer-events:none;
opacity: 1;
}
.nvd3 .nv-axis path {
fill: none;
stroke: #000;
stroke-opacity: .75;
shape-rendering: crispEdges;
}
.nvd3 .nv-axis path.domain {
stroke-opacity: .75;
}
.nvd3 .nv-axis.nv-x path.domain {
stroke-opacity: 0;
}
.nvd3 .nv-axis line {
fill: none;
stroke: #e5e5e5;
shape-rendering: crispEdges;
}
.nvd3 .nv-axis .zero line,
/*this selector may not be necessary*/ .nvd3 .nv-axis line.zero {
stroke-opacity: .75;
}
.nvd3 .nv-axis .nv-axisMaxMin text {
font-weight: bold;
}
.nvd3 .x .nv-axis .nv-axisMaxMin text,
.nvd3 .x2 .nv-axis .nv-axisMaxMin text,
.nvd3 .x3 .nv-axis .nv-axisMaxMin text {
text-anchor: middle
}
.nvd3 .nv-axis.nv-disabled {
opacity: 0;
}
/* scatter */
.nvd3 .nv-groups .nv-point.hover {
stroke-width: 20px;
stroke-opacity: .5;
}
.nvd3 .nv-scatter .nv-point.hover {
fill-opacity: 1;
}
.nv-noninteractive {
pointer-events: none;
}
.nv-distx, .nv-disty {
pointer-events: none;
}
.nvtooltip {
position: absolute;
background-color: rgba(255,255,255,1.0);
color: rgba(0,0,0,1.0);
padding: 1px;
border: 1px solid rgba(0,0,0,.2);
z-index: 10000;
display: block;
font-family: Arial;
font-size: 13px;
text-align: left;
pointer-events: none;
white-space: nowrap;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.nvtooltip {
background: rgba(255,255,255, 0.8);
border: 1px solid rgba(0,0,0,0.5);
border-radius: 4px;
}
/*Give tooltips that old fade in transition by
putting a "with-transitions" class on the container div.
*/
.nvtooltip.with-transitions, .with-transitions .nvtooltip {
transition: opacity 50ms linear;
-moz-transition: opacity 50ms linear;
-webkit-transition: opacity 50ms linear;
transition-delay: 200ms;
-moz-transition-delay: 200ms;
-webkit-transition-delay: 200ms;
}
.nvtooltip.x-nvtooltip,
.nvtooltip.y-nvtooltip {
padding: 8px;
}
.nvtooltip h3 {
margin: 0;
padding: 4px 14px;
line-height: 18px;
font-weight: normal;
background-color: rgba(247,247,247,0.75);
color: rgba(0,0,0,1.0);
text-align: center;
border-bottom: 1px solid #ebebeb;
-webkit-border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
border-radius: 5px 5px 0 0;
}
.nvtooltip p {
margin: 0;
padding: 5px 14px;
text-align: center;
}
.nvtooltip span {
display: inline-block;
margin: 2px 0;
}
.nvtooltip table {
margin: 6px;
border-spacing:0;
}
.nvtooltip table td {
padding: 2px 9px 2px 0;
vertical-align: middle;
}
.nvtooltip table td.key {
font-weight: normal;
}
.nvtooltip table td.key.total {
font-weight: bold;
}
.nvtooltip table td.value {
text-align: right;
font-weight: bold;
}
.nvtooltip table tr.highlight td {
padding: 1px 9px 1px 0;
border-bottom-style: solid;
border-bottom-width: 1px;
border-top-style: solid;
border-top-width: 1px;
}
.nvtooltip table td.legend-color-guide div {
width: 8px;
height: 8px;
vertical-align: middle;
}
.nvtooltip table td.legend-color-guide div {
width: 12px;
height: 12px;
border: 1px solid #999;
}
.nvtooltip .footer {
padding: 3px;
text-align: center;
}
.nvtooltip-pending-removal {
pointer-events: none;
display: none;
}
/****
Interactive Layer
*/
.nvd3 .nv-interactiveGuideLine {
pointer-events:none;
}
.nvd3 line.nv-guideline {
stroke: #ccc;
}
.nvd3 .nv-bars rect {
fill-opacity: .75;
transition: fill-opacity 250ms linear;
-moz-transition: fill-opacity 250ms linear;
-webkit-transition: fill-opacity 250ms linear;
}
.nvd3 .nv-bars rect.hover {
fill-opacity: 1;
}
.nvd3 .nv-bars .hover rect {
fill: lightblue;
}
.nvd3 .nv-bars text {
fill: rgba(0,0,0,0);
}
.nvd3 .nv-bars .hover text {
fill: rgba(0,0,0,1);
}
.nvd3 .nv-multibar .nv-groups rect,
.nvd3 .nv-multibarHorizontal .nv-groups rect,
.nvd3 .nv-discretebar .nv-groups rect {
stroke-opacity: 0;
transition: fill-opacity 250ms linear;
-moz-transition: fill-opacity 250ms linear;
-webkit-transition: fill-opacity 250ms linear;
}
.nvd3 .nv-multibar .nv-groups rect:hover,
.nvd3 .nv-multibarHorizontal .nv-groups rect:hover,
.nvd3 .nv-candlestickBar .nv-ticks rect:hover,
.nvd3 .nv-discretebar .nv-groups rect:hover {
fill-opacity: 1;
}
.nvd3 .nv-discretebar .nv-groups text,
.nvd3 .nv-multibarHorizontal .nv-groups text {
font-weight: bold;
fill: rgba(0,0,0,1);
stroke: rgba(0,0,0,0);
}
.nvd3 .nv-groups path.nv-line {
fill: none;
}
.nvd3 .nv-groups path.nv-area {
stroke: none;
}
.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point {
fill-opacity: 0;
stroke-opacity: 0;
}
.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point {
fill-opacity: .5 !important;
stroke-opacity: .5 !important;
}
.with-transitions .nvd3 .nv-groups .nv-point {
transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
}
.nvd3.nv-scatter .nv-groups .nv-point.hover,
.nvd3 .nv-groups .nv-point.hover {
stroke-width: 7px;
fill-opacity: .95 !important;
stroke-opacity: .95 !important;
}
.nvd3 .nv-point-paths path {
stroke: #aaa;
stroke-opacity: 0;
fill: #eee;
fill-opacity: 0;
}
.nvd3 .nv-indexLine {
cursor: ew-resize;
}
/********************
* SVG CSS
*/
/********************
Default CSS for an svg element nvd3 used
*/
svg.nvd3-svg {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-ms-user-select: none;
-moz-user-select: none;
user-select: none;
display: block;
width:100%;
height:100%;
}
/********************
Box shadow and border radius styling
*/
.nvtooltip.with-3d-shadow, .with-3d-shadow .nvtooltip {
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
box-shadow: 0 5px 10px rgba(0,0,0,.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
.nvd3 text {
font: normal 12px Arial;
}
.nvd3 .title {
font: bold 14px Arial;
}
.nvd3 .nv-background {
fill: white;
fill-opacity: 0;
}
.nvd3.nv-noData {
font-size: 18px;
font-weight: bold;
}
/**********
* Brush
*/
.nv-brush .extent {
fill-opacity: .125;
shape-rendering: crispEdges;
}
.nv-brush .resize path {
fill: #eee;
stroke: #666;
}
/**********
* Legend
*/
.nvd3 .nv-legend .nv-series {
cursor: pointer;
}
.nvd3 .nv-legend .nv-disabled circle {
fill-opacity: 0;
}
/* focus */
.nvd3 .nv-brush .extent {
fill-opacity: 0 !important;
}
.nvd3 .nv-brushBackground rect {
stroke: #000;
stroke-width: .4;
fill: #fff;
fill-opacity: .7;
}
.nvd3.nv-pie path {
stroke-opacity: 0;
transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
-moz-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
-webkit-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
}
.nvd3.nv-pie .nv-pie-title {
font-size: 24px;
fill: rgba(19, 196, 249, 0.59);
}
.nvd3.nv-pie .nv-slice text {
stroke: #000;
stroke-width: 0;
}
.nvd3.nv-pie path {
stroke: #fff;
stroke-width: 1px;
stroke-opacity: 1;
}
.nvd3.nv-pie path {
fill-opacity: .7;
}
.nvd3.nv-pie .hover path {
fill-opacity: 1;
}
.nvd3.nv-pie .nv-label {
pointer-events: none;
}
.nvd3.nv-pie .nv-label rect {
fill-opacity: 0;
stroke-opacity: 0;
}

5985
kpi_dashboard/static/lib/nvd3/nv.d3.js
File diff suppressed because it is too large
View File

7
kpi_dashboard/static/src/js/dashboard_controller.js

@ -1,3 +1,6 @@
/*
global py
*/
odoo.define("kpi_dashboard.DashboardController", function(require) { odoo.define("kpi_dashboard.DashboardController", function(require) {
"use strict"; "use strict";
@ -20,7 +23,7 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
add_modify_color: "_addModifyColor", add_modify_color: "_addModifyColor",
refresh_colors: "_refreshColors", refresh_colors: "_refreshColors",
}), }),
_refreshOnFly: function(event) {
_refreshOnFly: function() {
var self = this; var self = this;
this._rpc({ this._rpc({
model: this.modelName, model: this.modelName,
@ -37,12 +40,14 @@ odoo.define("kpi_dashboard.DashboardController", function(require) {
}); });
}, },
renderPager: function($node, options) { renderPager: function($node, options) {
// 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
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;

2
kpi_dashboard/static/src/js/dashboard_model.js

@ -4,7 +4,7 @@ odoo.define("kpi_dashboard.DashboardModel", function(require) {
var BasicModel = require("web.BasicModel"); var BasicModel = require("web.BasicModel");
var DashboardModel = BasicModel.extend({ var DashboardModel = BasicModel.extend({
_fetchRecord: function(record, options) {
_fetchRecord: function(record) {
return this._rpc({ return this._rpc({
model: record.model, model: record.model,
method: "read_dashboard", method: "read_dashboard",

1
kpi_dashboard/static/src/js/dashboard_renderer.js

@ -4,7 +4,6 @@ odoo.define("kpi_dashboard.DashboardRenderer", function(require) {
var BasicRenderer = require("web.BasicRenderer"); var BasicRenderer = require("web.BasicRenderer");
var core = require("web.core"); var core = require("web.core");
var registry = require("kpi_dashboard.widget_registry"); var registry = require("kpi_dashboard.widget_registry");
var BusService = require("bus.BusService");
var qweb = core.qweb; var qweb = core.qweb;
var DashboardRenderer = BasicRenderer.extend({ var DashboardRenderer = BasicRenderer.extend({

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

@ -0,0 +1,50 @@
/*
global nv
*/
odoo.define("web.nvd3.extensions", function() {
"use strict";
/**
* The nvd3 library extensions and fixes should be done here to avoid patching
* in place.
*/
nv.dev = false;
// Sets nvd3 library in production mode
// monkey patch nvd3 to allow removing eventhandler on windowresize events
// see https://github.com/novus/nvd3/pull/396 for more details
// Adds a resize listener to the window.
nv.utils.onWindowResize = function(fun) {
if (fun === null) return;
window.addEventListener("resize", fun);
};
// Backwards compatibility with current API.
nv.utils.windowResize = nv.utils.onWindowResize;
// Removes a resize listener from the window.
nv.utils.offWindowResize = function(fun) {
if (fun === null) return;
window.removeEventListener("resize", fun);
};
// Monkey patch nvd3 to prevent crashes when user changes view and nvd3
// tries to remove tooltips after 500 ms... seriously nvd3, what were you
// thinking?
nv.tooltip.cleanup = function() {
$(".nvtooltip").remove();
};
// Monkey patch nvd3 to prevent it to display a tooltip (position: absolute)
// with a negative `top`; with this patch the highest tooltip's position is
// still in the graph
var originalCalcTooltipPosition = nv.tooltip.calcTooltipPosition;
nv.tooltip.calcTooltipPosition = function() {
var container = originalCalcTooltipPosition.apply(this, arguments);
container.style.top =
container.style.top.split("px")[0] < 0 ? 0 + "px" : container.style.top;
return container;
};
});

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

@ -7,9 +7,12 @@ odoo.define("kpi_dashboard.AbstractWidget", function(require) {
var registry = require("kpi_dashboard.widget_registry"); var registry = require("kpi_dashboard.widget_registry");
var AbstractWidget = Widget.extend({ var AbstractWidget = Widget.extend({
template: "kpi_dashboard.base_widget", // Template used by the widget
cssLibs: [], // Specific css of the widget
jsLibs: [], // Specific Javascript libraries of the widget
// Template used by the widget
template: "kpi_dashboard.base_widget",
// Specific css of the widget
cssLibs: [],
// Specific Javascript libraries of the widget
jsLibs: [],
events: { events: {
"click .o_kpi_dashboard_toggle_button": "_onClickToggleButton", "click .o_kpi_dashboard_toggle_button": "_onClickToggleButton",
"click .direct_action": "_onClickDirectAction", "click .direct_action": "_onClickDirectAction",

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

@ -3,7 +3,6 @@ odoo.define("kpi_dashboard.CounterWidget", function(require) {
var IntegerWidget = require("kpi_dashboard.IntegerWidget"); var IntegerWidget = require("kpi_dashboard.IntegerWidget");
var registry = require("kpi_dashboard.widget_registry"); var registry = require("kpi_dashboard.widget_registry");
var field_utils = require("web.field_utils");
var CounterWidget = IntegerWidget.extend({ var CounterWidget = IntegerWidget.extend({
shortList: [], shortList: [],

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

@ -1,3 +1,6 @@
/*
global nv, d3
*/
odoo.define("kpi_dashboard.GraphWidget", function(require) { odoo.define("kpi_dashboard.GraphWidget", function(require) {
"use strict"; "use strict";
@ -9,11 +12,11 @@ odoo.define("kpi_dashboard.GraphWidget", function(require) {
var GraphWidget = AbstractWidget.extend({ var GraphWidget = AbstractWidget.extend({
template: "kpi_dashboard.graph", template: "kpi_dashboard.graph",
jsLibs: [ jsLibs: [
"/web/static/lib/nvd3/d3.v3.js",
"/web/static/lib/nvd3/nv.d3.js",
"/web/static/src/js/libs/nvd3.js",
"/kpi_dashboard/static/lib/nvd3/d3.v3.js",
"/kpi_dashboard/static/lib/nvd3/nv.d3.js",
"/kpi_dashboard/static/src/js/lib/nvd3.js",
], ],
cssLibs: ["/web/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);
@ -28,7 +31,7 @@ odoo.define("kpi_dashboard.GraphWidget", function(require) {
} }
this._super.apply(this, arguments); this._super.apply(this, arguments);
}, },
_getChartOptions: function(values) {
_getChartOptions: function() {
return { return {
x: function(d, u) { x: function(d, u) {
return u; return u;

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

@ -18,16 +18,17 @@ odoo.define("kpi_dashboard.IntegerWidget", function(require) {
var suffix = ""; var suffix = "";
var shortened = false; var shortened = false;
var digits = this.digits; var digits = this.digits;
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];
num /= shortItem[0];
result /= shortItem[0];
digits = shortItem[2]; digits = shortItem[2];
} }
}); });
return ( return (
field_utils.format.float(num, false, {
field_utils.format.float(result, false, {
digits: digits, digits: digits,
}) + suffix }) + suffix
); );

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

@ -21,8 +21,8 @@ odoo.define("kpi_dashboard.MeterWidget", function(require) {
style: "Arch", style: "Arch",
width: 10, width: 10,
size: size, size: size,
prepend: values.prefix !== undefined ? values.prefix : "",
append: values.suffix !== undefined ? values.suffix : "",
prepend: values.prefix === undefined ? "" : values.prefix,
append: values.suffix === undefined ? "" : values.suffix,
color: values.font_color, color: values.font_color,
animate_text_colors: true, animate_text_colors: true,
}; };

8
kpi_dashboard/tests/test_formula.py

@ -9,7 +9,7 @@ class TestFormula(TransactionCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.kpi = self.env["kpi.kpi"].create( self.kpi = self.env["kpi.kpi"].create(
{"name": "DEMO KPI", "widget": "number", "computation_method": "code",}
{"name": "DEMO KPI", "widget": "number", "computation_method": "code"}
) )
def test_forbidden_words_01(self): def test_forbidden_words_01(self):
@ -45,8 +45,7 @@ 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
@ -66,8 +65,7 @@ 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

4
kpi_dashboard/tests/test_kpi_dashboard.py

@ -53,16 +53,18 @@ class TestKpiDashboard(TransactionCase):
} }
) )
self.env["kpi.dashboard.item"].create( self.env["kpi.dashboard.item"].create(
{"dashboard_id": self.dashboard.id, "name": "TITLE", "row": 2, "column": 1,}
{"dashboard_id": self.dashboard.id, "name": "TITLE", "row": 2, "column": 1}
) )
def test_constrains_01(self): def test_constrains_01(self):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.kpi_01.dashboard_item_ids.write({"size_x": 2}) self.kpi_01.dashboard_item_ids.write({"size_x": 2})
self.kpi_01.flush()
def test_constrains_02(self): def test_constrains_02(self):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.kpi_02.dashboard_item_ids.write({"size_x": 4}) self.kpi_02.dashboard_item_ids.write({"size_x": 4})
self.kpi_01.flush()
def test_constrains_03(self): def test_constrains_03(self):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):

3
kpi_dashboard/wizards/kpi_dashboard_menu.py

@ -1,7 +1,7 @@
# Copyright 2020 Creu Blanca # Copyright 2020 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo import fields, models
class KpiDashboardMenu(models.TransientModel): class KpiDashboardMenu(models.TransientModel):
@ -12,6 +12,5 @@ class KpiDashboardMenu(models.TransientModel):
dashboard_id = fields.Many2one("kpi.dashboard", required=True) dashboard_id = fields.Many2one("kpi.dashboard", required=True)
menu_id = fields.Many2one("ir.ui.menu") menu_id = fields.Many2one("ir.ui.menu")
@api.multi
def generate_menu(self): def generate_menu(self):
self.dashboard_id._generate_menu(self.menu_id) self.dashboard_id._generate_menu(self.menu_id)
Loading…
Cancel
Save