Browse Source

[13.0][MIG] bi_view_editor

myc-14.0-py3o
Andrea 4 years ago
parent
commit
fd47f75e72
  1. 2
      bi_view_editor/__init__.py
  2. 5
      bi_view_editor/__manifest__.py
  3. 48
      bi_view_editor/hooks.py
  4. 0
      bi_view_editor/i18n/nl.po
  5. 34
      bi_view_editor/models/bve_view.py
  6. 49
      bi_view_editor/models/bve_view_line.py
  7. 24
      bi_view_editor/models/ir_model.py
  8. 1
      bi_view_editor/models/models.py
  9. 7
      bi_view_editor/readme/USAGE.rst
  10. 5
      bi_view_editor/static/src/css/bve.css
  11. 72
      bi_view_editor/static/src/js/bi_view_editor.FieldList.js
  12. 4
      bi_view_editor/static/src/js/bi_view_editor.ModelList.js
  13. 40
      bi_view_editor/static/src/js/bi_view_editor.js
  14. 24
      bi_view_editor/static/src/xml/bi_view_editor.xml
  15. 33
      bi_view_editor/tests/test_bi_view.py
  16. 18
      bi_view_editor/views/bve_view.xml

2
bi_view_editor/__init__.py

@ -2,4 +2,4 @@
from . import models from . import models
from . import wizard from . import wizard
from .hooks import post_load, uninstall_hook
from .hooks import uninstall_hook

5
bi_view_editor/__manifest__.py

@ -9,9 +9,9 @@
"license": "AGPL-3", "license": "AGPL-3",
"website": "https://github.com/OCA/reporting-engine", "website": "https://github.com/OCA/reporting-engine",
"category": "Reporting", "category": "Reporting",
"version": "12.0.1.0.0",
"version": "13.0.1.0.0",
"development_status": "Beta", "development_status": "Beta",
"depends": ["web",],
"depends": ["web"],
"data": [ "data": [
"security/ir.model.access.csv", "security/ir.model.access.csv",
"security/rules.xml", "security/rules.xml",
@ -19,7 +19,6 @@
"views/bve_view.xml", "views/bve_view.xml",
], ],
"qweb": ["static/src/xml/bi_view_editor.xml"], "qweb": ["static/src/xml/bi_view_editor.xml"],
"post_load": "post_load",
"uninstall_hook": "uninstall_hook", "uninstall_hook": "uninstall_hook",
"installable": True, "installable": True,
} }

48
bi_view_editor/hooks.py

@ -1,54 +1,6 @@
# Copyright 2015-2019 Onestein (<https://www.onestein.eu>) # Copyright 2015-2019 Onestein (<https://www.onestein.eu>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import logging
from odoo import SUPERUSER_ID, api, modules
from odoo.tools import existing_tables, topological_sort
_logger = logging.getLogger(__name__)
def _bi_view(_name):
return _name.startswith("x_bve.")
def post_load():
def check_tables_exist(self, cr):
"""
Verify that all tables are present and try to initialize
those that are missing.
"""
# This monkey patch is meant to avoid that the _logger writes
# warning and error messages, while running an update all,
# in case the model is a bi-view-generated model.
env = api.Environment(cr, SUPERUSER_ID, {})
table2model = {
model._table: name
for name, model in env.items()
if not model._abstract and not _bi_view(name) # here is the patch
}
missing_tables = set(table2model).difference(existing_tables(cr, table2model))
if missing_tables:
missing = {table2model[table] for table in missing_tables}
_logger.warning("Models have no table: %s.", ", ".join(missing))
# recreate missing tables following model dependencies
deps = {name: model._depends for name, model in env.items()}
for name in topological_sort(deps):
if name in missing:
_logger.info("Recreate table of model %s.", name)
env[name].init()
# check again, and log errors if tables are still missing
missing_tables = set(table2model).difference(
existing_tables(cr, table2model)
)
for table in missing_tables:
_logger.error("Model %s has no table.", table2model[table])
modules.registry.Registry.check_tables_exist = check_tables_exist
def uninstall_hook(cr, registry): def uninstall_hook(cr, registry):
# delete dirty data that could cause problems # delete dirty data that could cause problems

0
bi_view_editor/i18n/nl.po

34
bi_view_editor/models/bve_view.py

@ -60,7 +60,7 @@ class BveView(models.Model):
line_ids = self._sync_lines_and_data(bve_view.data) line_ids = self._sync_lines_and_data(bve_view.data)
bve_view.write({"line_ids": line_ids}) bve_view.write({"line_ids": line_ids})
name = fields.Char(required=True, copy=False)
name = fields.Char(required=True, copy=False, default="")
model_name = fields.Char(compute="_compute_model_name", store=True) model_name = fields.Char(compute="_compute_model_name", store=True)
note = fields.Text(string="Notes") note = fields.Text(string="Notes")
state = fields.Selection( state = fields.Selection(
@ -100,7 +100,7 @@ class BveView(models.Model):
) )
query = fields.Text(compute="_compute_sql_query") query = fields.Text(compute="_compute_sql_query")
over_condition = fields.Text( over_condition = fields.Text(
states={"draft": [("readonly", False),],},
states={"draft": [("readonly", False)]},
readonly=True, readonly=True,
help="Condition to be inserted in the OVER part " help="Condition to be inserted in the OVER part "
"of the ID's row_number function.\n" "of the ID's row_number function.\n"
@ -169,7 +169,7 @@ class BveView(models.Model):
try: try:
png_base64_image = base64.b64encode(graph.create_png()) png_base64_image = base64.b64encode(graph.create_png())
bve_view.er_diagram_image = png_base64_image bve_view.er_diagram_image = png_base64_image
except:
except Exception:
bve_view.er_diagram_image = False bve_view.er_diagram_image = False
def _create_view_arch(self): def _create_view_arch(self):
@ -191,7 +191,7 @@ class BveView(models.Model):
return '<field name="{}" {} />'.format(line.name, res) return '<field name="{}" {} />'.format(line.name, res)
bve_field_lines = self.field_ids.filtered(lambda l: l.in_list) bve_field_lines = self.field_ids.filtered(lambda l: l.in_list)
return list(map(_get_field_attrs, bve_field_lines))
return list(map(_get_field_attrs, bve_field_lines.sorted("sequence")))
def _create_bve_view(self): def _create_bve_view(self):
self.ensure_one() self.ensure_one()
@ -236,7 +236,7 @@ class BveView(models.Model):
"model": self.model_name, "model": self.model_name,
"priority": 16, "priority": 16,
"arch": """<?xml version="1.0"?> "arch": """<?xml version="1.0"?>
<search string="Search BI View">
<search>
{} {}
</search> </search>
""".format( """.format(
@ -254,7 +254,7 @@ class BveView(models.Model):
"model": self.model_name, "model": self.model_name,
"priority": 16, "priority": 16,
"arch": """<?xml version="1.0"?> "arch": """<?xml version="1.0"?>
<tree string="List Analysis" create="false">
<tree create="false">
{} {}
</tree> </tree>
""".format( """.format(
@ -272,7 +272,6 @@ class BveView(models.Model):
"name": self.name, "name": self.name,
"res_model": self.model_name, "res_model": self.model_name,
"type": "ir.actions.act_window", "type": "ir.actions.act_window",
"view_type": "form",
"view_mode": "tree,graph,pivot", "view_mode": "tree,graph,pivot",
"view_id": tree_view.id, "view_id": tree_view.id,
"context": "{'service_name': '%s'}" % self.name, "context": "{'service_name': '%s'}" % self.name,
@ -475,7 +474,7 @@ class BveView(models.Model):
self.env["ir.model.access"] self.env["ir.model.access"]
.sudo() .sudo()
.search( .search(
[("model_id", "=", line_model.id), ("perm_read", "=", True),]
[("model_id", "=", line_model.id), ("perm_read", "=", True)]
) )
) )
group_list = "" group_list = ""
@ -495,20 +494,18 @@ class BveView(models.Model):
if not self.line_ids: if not self.line_ids:
raise ValidationError(_("No data to process.")) raise ValidationError(_("No data to process."))
if any(not line.model_id for line in self.line_ids):
invalid_lines = self.line_ids.filtered(lambda l: not l.model_id)
missing_models = set(invalid_lines.mapped("model_name"))
missing_models = ", ".join(missing_models)
invalid_lines = self.line_ids.filtered(lambda l: not l.model_id)
if invalid_lines:
missing_models = ", ".join(set(invalid_lines.mapped("model_name")))
raise ValidationError( raise ValidationError(
_( _(
"Following models are missing: %s.\n" "Following models are missing: %s.\n"
"Probably some modules were uninstalled." % (missing_models,) "Probably some modules were uninstalled." % (missing_models,)
) )
) )
if any(not line.field_id for line in self.line_ids):
invalid_lines = self.line_ids.filtered(lambda l: not l.field_id)
missing_fields = set(invalid_lines.mapped("field_name"))
missing_fields = ", ".join(missing_fields)
invalid_lines = self.line_ids.filtered(lambda l: not l.field_id)
if invalid_lines:
missing_fields = ", ".join(set(invalid_lines.mapped("field_name")))
raise ValidationError( raise ValidationError(
_("Following fields are missing: {}.".format(missing_fields)) _("Following fields are missing: {}.".format(missing_fields))
) )
@ -520,7 +517,6 @@ class BveView(models.Model):
action["display_name"] = _("BI View") action["display_name"] = _("BI View")
return action return action
@api.multi
def copy(self, default=None): def copy(self, default=None):
self.ensure_one() self.ensure_one()
default = dict(default or {}, name=_("%s (copy)") % self.name) default = dict(default or {}, name=_("%s (copy)") % self.name)
@ -623,7 +619,9 @@ class BveView(models.Model):
@api.model @api.model
def get_clean_list(self, data_dict): def get_clean_list(self, data_dict):
serialized_data = json.loads(data_dict)
serialized_data = data_dict
if type(data_dict) == str:
serialized_data = json.loads(data_dict)
table_alias_list = set() table_alias_list = set()
for item in serialized_data: for item in serialized_data:
if item.get("join_node", -1) in [-1, False]: if item.get("join_node", -1) in [-1, False]:

49
bi_view_editor/models/bve_view_line.py

@ -1,4 +1,4 @@
# Copyright 2015-2019 Onestein (<https://www.onestein.eu>)
# Copyright 2015-2020 Onestein (<https://www.onestein.eu>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models from odoo import _, api, fields, models
@ -12,11 +12,11 @@ class BveViewLine(models.Model):
name = fields.Char(compute="_compute_name") name = fields.Char(compute="_compute_name")
sequence = fields.Integer(default=1) sequence = fields.Integer(default=1)
bve_view_id = fields.Many2one("bve.view", ondelete="cascade") bve_view_id = fields.Many2one("bve.view", ondelete="cascade")
model_id = fields.Many2one("ir.model", string="Model")
model_name = fields.Char(compute="_compute_model_name", store=True)
table_alias = fields.Char()
join_model_id = fields.Many2one("ir.model", string="Join Model")
field_id = fields.Many2one("ir.model.fields", string="Field")
model_id = fields.Many2one("ir.model")
model_name = fields.Char(related="model_id.model", store=True, string="Model Name")
table_alias = fields.Char(required=True)
join_model_id = fields.Many2one("ir.model")
field_id = fields.Many2one("ir.model.fields")
field_name = fields.Char(compute="_compute_model_field_name", store=True) field_name = fields.Char(compute="_compute_model_field_name", store=True)
ttype = fields.Char(string="Type") ttype = fields.Char(string="Type")
description = fields.Char(translate=True) description = fields.Char(translate=True)
@ -29,7 +29,7 @@ class BveViewLine(models.Model):
measure = fields.Boolean() measure = fields.Boolean()
in_list = fields.Boolean() in_list = fields.Boolean()
list_attr = fields.Selection( list_attr = fields.Selection(
[("sum", "Sum"), ("avg", "Average"),], string="List Attribute", default="sum"
[("sum", "Sum"), ("avg", "Average")], string="List Attribute", default="sum"
) )
view_field_type = fields.Char(compute="_compute_view_field_type") view_field_type = fields.Char(compute="_compute_view_field_type")
@ -44,14 +44,13 @@ class BveViewLine(models.Model):
@api.constrains("row", "column", "measure") @api.constrains("row", "column", "measure")
def _constrains_options_check(self): def _constrains_options_check(self):
measure_types = ["float", "integer", "monetary"] measure_types = ["float", "integer", "monetary"]
for line in self.filtered(lambda l: l.row or l.column):
if line.join_model_id or line.ttype in measure_types:
err_msg = _("This field cannot be a row or a column.")
raise ValidationError(err_msg)
for line in self.filtered(lambda l: l.measure):
if line.join_model_id or line.ttype not in measure_types:
err_msg = _("This field cannot be a measure.")
raise ValidationError(err_msg)
lines = self.filtered(lambda l: l.join_model_id or l.ttype in measure_types)
if lines.filtered(lambda l: l.row or l.column):
err_msg = _("This field cannot be a row or a column.")
raise ValidationError(err_msg)
if lines.filtered(lambda l: l.measure):
err_msg = _("This field cannot be a measure.")
raise ValidationError(err_msg)
@api.constrains("table_alias", "field_id") @api.constrains("table_alias", "field_id")
def _constrains_unique_fields_check(self): def _constrains_unique_fields_check(self):
@ -67,21 +66,17 @@ class BveViewLine(models.Model):
@api.depends("field_id", "sequence") @api.depends("field_id", "sequence")
def _compute_name(self): def _compute_name(self):
for line in self.filtered(lambda l: l.field_id):
field_name = line.field_id.name
line.name = "x_bve_{}_{}".format(line.table_alias, field_name)
@api.depends("model_id")
def _compute_model_name(self):
for line in self.filtered(lambda l: l.model_id):
line.model_name = line.model_id.model
for line in self:
line.name = False
if line.field_id:
line.name = "x_bve_{}_{}".format(line.table_alias, line.field_id.name)
@api.depends("field_id") @api.depends("field_id")
def _compute_model_field_name(self): def _compute_model_field_name(self):
for line in self.filtered(lambda l: l.field_id):
field_name = line.description
model_name = line.model_name
line.field_name = "{} ({})".format(field_name, model_name)
for line in self:
line.field_name = False
if line.field_id:
line.field_name = "{} ({})".format(line.description, line.model_name)
def _prepare_field_vals(self): def _prepare_field_vals(self):
vals_list = [] vals_list = []

24
bi_view_editor/models/ir_model.py

@ -3,7 +3,7 @@
from collections import defaultdict from collections import defaultdict
from odoo import api, models, registry
from odoo import api, models
NO_BI_MODELS = ["fetchmail.server"] NO_BI_MODELS = ["fetchmail.server"]
@ -212,25 +212,3 @@ class IrModel(models.Model):
) )
fields_dict = list(map(dict_for_field, fields)) fields_dict = list(map(dict_for_field, fields))
return fields_dict return fields_dict
@api.model
def create(self, vals):
if self.env.context and self.env.context.get("bve"):
vals["state"] = "base"
res = super().create(vals)
# this sql update is necessary since a write method here would
# be not working (an orm constraint is restricting the modification
# of the state field while updating ir.model)
q = "UPDATE ir_model SET state = 'manual' WHERE id = %s"
self.env.cr.execute(q, (res.id,))
# # update registry
if self.env.context.get("bve"):
# setup models; this reloads custom models in registry
self.pool.setup_models(self._cr)
# signal that registry has changed
registry(self.env.cr.dbname).signal_changes()
return res

1
bi_view_editor/models/models.py

@ -17,7 +17,6 @@ def _bi_view(_name):
_auto_init_orig = models.BaseModel._auto_init _auto_init_orig = models.BaseModel._auto_init
@api.model_cr_context
def _auto_init(self): def _auto_init(self):
# This monkey patch is meant to fix an error (probably # This monkey patch is meant to fix an error (probably

7
bi_view_editor/readme/USAGE.rst

@ -22,5 +22,8 @@ A more advanced UI is also available under the "Details" tab. It provides extra
possibilities for more advanced users, like to use LEFT JOIN instead of the possibilities for more advanced users, like to use LEFT JOIN instead of the
default INNER JOIN. default INNER JOIN.
It also possible to improve the IDs generation for new views by adding an `Over Condition` in the "SQL" tab, see https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS for further details.
For instance, an ORDER BY clause helps preventing unreliable behavior when filtering the generated views.
It also possible to improve the IDs generation for new views by adding an
`Over Condition` in the "SQL" tab, see https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS
for further details.
For instance, an ORDER BY clause helps preventing unreliable behavior when
filtering the generated views.

5
bi_view_editor/static/src/css/bve.css

@ -159,11 +159,6 @@
width: 175px; width: 175px;
} }
.oe_form_field_bi_editor .context-menu .checkbox {
margin-top: 0px;
margin-bottom: 0px;
}
.oe_form_field_bi_editor .context-menu .checkbox label { .oe_form_field_bi_editor .context-menu .checkbox label {
display: block; display: block;
} }

72
bi_view_editor/static/src/js/bi_view_editor.FieldList.js

@ -7,28 +7,32 @@ odoo.define("bi_view_editor.FieldList", function(require) {
var core = require("web.core"); var core = require("web.core");
var qweb = core.qweb; var qweb = core.qweb;
var Widget = require("web.Widget"); var Widget = require("web.Widget");
var mixins = require("web.mixins");
var FieldListContextMenu = Widget.extend({
start: function() {
var res = this._super.apply(this, arguments);
this.$el.mouseleave(function() {
$(this).addClass("d-none");
});
return res;
},
open: function(x, y) {
this.$el.css({
left: x + "px",
top: y + "px",
});
this.$el.removeClass("d-none");
return _.extend({}, window.Backbone.Events);
},
});
var FieldListContextMenu = Widget.extend(
_.extend({}, mixins.EventDispatcherMixin, {
start: function() {
var res = this._super.apply(this, arguments);
this.$el.mouseleave(function() {
$(this).addClass("d-none");
});
return res;
},
open: function(x, y) {
this.$el.css({
left: x + "px",
top: y + "px",
});
this.$el.removeClass("d-none");
return this;
},
})
);
var FieldListFieldContextMenu = FieldListContextMenu.extend({ var FieldListFieldContextMenu = FieldListContextMenu.extend({
template: "bi_view_editor.FieldList.FieldContextMenu", template: "bi_view_editor.FieldList.FieldContextMenu",
open: function(x, y, field) {
open: function(x, y, $item) {
var field = $item.data("field");
this.$el.find(".checkbox-column").prop("checked", field.column); this.$el.find(".checkbox-column").prop("checked", field.column);
this.$el.find(".checkbox-row").prop("checked", field.row); this.$el.find(".checkbox-row").prop("checked", field.row);
this.$el.find(".checkbox-measure").prop("checked", field.measure); this.$el.find(".checkbox-measure").prop("checked", field.measure);
@ -49,7 +53,7 @@ odoo.define("bi_view_editor.FieldList", function(require) {
var $checkbox = $(this); var $checkbox = $(this);
var property = $checkbox.attr("data-for"); var property = $checkbox.attr("data-for");
field[property] = $checkbox.is(":checked"); field[property] = $checkbox.is(":checked");
events.trigger("change", field);
events.trigger("change", field, $item);
}); });
return events; return events;
@ -58,7 +62,8 @@ odoo.define("bi_view_editor.FieldList", function(require) {
var FieldListJoinContextMenu = FieldListContextMenu.extend({ var FieldListJoinContextMenu = FieldListContextMenu.extend({
template: "bi_view_editor.FieldList.JoinContextMenu", template: "bi_view_editor.FieldList.JoinContextMenu",
open: function(x, y, node) {
open: function(x, y, $item) {
var node = $item.data("field");
this.$el.find(".checkbox-join-left").prop("checked", node.join_left); this.$el.find(".checkbox-join-left").prop("checked", node.join_left);
var events = this._super(x, y, node); var events = this._super(x, y, node);
@ -83,8 +88,26 @@ odoo.define("bi_view_editor.FieldList", function(require) {
var res = this._super.apply(this, arguments); var res = this._super.apply(this, arguments);
this.contextmenu = new FieldListFieldContextMenu(this); this.contextmenu = new FieldListFieldContextMenu(this);
this.contextmenu.appendTo(this.$el); this.contextmenu.appendTo(this.$el);
this.contextmenu.on(
"change",
this,
function(f, $item) {
$item.data("field", f);
this.refreshItem($item);
this.trigger("updated");
}.bind(this)
);
this.contextmenu_join = new FieldListJoinContextMenu(this); this.contextmenu_join = new FieldListJoinContextMenu(this);
this.contextmenu_join.appendTo(this.$el); this.contextmenu_join.appendTo(this.$el);
this.contextmenu_join.on(
"change",
this,
function(f, $item) {
$item.data("field", f);
this.refreshItem($item);
this.trigger("updated");
}.bind(this)
);
this.$table = this.$el.find("tbody"); this.$table = this.$el.find("tbody");
this.mode = null; this.mode = null;
return res; return res;
@ -201,14 +224,7 @@ odoo.define("bi_view_editor.FieldList", function(require) {
if (field.join_node) { if (field.join_node) {
return; return;
} }
contextmenu.open(x - 20, y - 20, $item.data("field")).on(
"change",
function(f) {
$item.data("field", f);
this.refreshItem($item);
this.trigger("updated");
}.bind(this)
);
contextmenu.open(x - 20, y - 20, $item);
}, },
refreshItem: function($item) { refreshItem: function($item) {
var data = $item.data("field"); var data = $item.data("field");

4
bi_view_editor/static/src/js/bi_view_editor.ModelList.js

@ -80,7 +80,7 @@ odoo.define("bi_view_editor.ModelList", function(require) {
self.$el.find(".class-list").append($html); self.$el.find(".class-list").append($html);
if (self.isActive(model.id)) { if (self.isActive(model.id)) {
self.loadFields(model.id).done(function(fields) {
self.loadFields(model.id).then(function(fields) {
self.populateFields(fields, model.id); self.populateFields(fields, model.id);
}); });
} }
@ -129,7 +129,7 @@ odoo.define("bi_view_editor.ModelList", function(require) {
this.removeAsActive(model.id); this.removeAsActive(model.id);
} else { } else {
this.addAsActive(model.id); this.addAsActive(model.id);
this.loadFields(model.id).done(
this.loadFields(model.id).then(
function(fields) { function(fields) {
this.populateFields(fields, model.id); this.populateFields(fields, model.id);
}.bind(this) }.bind(this)

40
bi_view_editor/static/src/js/bi_view_editor.js

@ -30,24 +30,27 @@ odoo.define("bi_view_editor", function(require) {
// Init FieldList // Init FieldList
this.field_list = new FieldList(this); this.field_list = new FieldList(this);
this.field_list.appendTo(this.$(".body > .right"));
this.field_list.on("removed", this, this.fieldListRemoved);
this.field_list.on("updated", this, this.fieldListChanged);
this.field_list.appendTo(this.$(".body > .right")).then(
function() {
this.field_list.on("removed", this, this.fieldListRemoved);
this.field_list.on("updated", this, this.fieldListChanged);
this.$el.find(".body > .right").droppable({
accept: "div.class-list div.field",
drop: function(event, ui) {
self.addField(_.extend({}, ui.draggable.data("field")));
ui.draggable.draggable("option", "revert", false);
},
});
this.$el.find(".body > .right").droppable({
accept: "div.class-list div.field",
drop: function(event, ui) {
self.addField(_.extend({}, ui.draggable.data("field")));
ui.draggable.draggable("option", "revert", false);
},
});
this.on("change:effective_readonly", this, function() {
this.updateMode();
});
this.renderValue();
this.loadAndPopulateModelList();
this.updateMode();
}.bind(this)
);
this.on("change:effective_readonly", this, function() {
this.updateMode();
});
this.renderValue();
this.loadAndPopulateModelList();
this.updateMode();
return res; return res;
}, },
clear: function() { clear: function() {
@ -61,10 +64,9 @@ odoo.define("bi_view_editor", function(require) {
this._setValue(this.field_list.get()); this._setValue(this.field_list.get());
}, },
fieldListRemoved: function() { fieldListRemoved: function() {
console.log(this.field_list.get());
this._setValue(this.field_list.get()); this._setValue(this.field_list.get());
var model = new Data.DataSet(this, "bve.view"); var model = new Data.DataSet(this, "bve.view");
model.call("get_clean_list", [this.value]).then(
model.call("get_clean_list", [this.lastSetValue]).then(
function(result) { function(result) {
this.field_list.set(JSON.parse(result)); this.field_list.set(JSON.parse(result));
this._setValue(this.field_list.get()); this._setValue(this.field_list.get());
@ -91,7 +93,7 @@ odoo.define("bi_view_editor", function(require) {
if (this.field_list.get().length > 0) { if (this.field_list.get().length > 0) {
model_ids = this.field_list.getModelIds(); model_ids = this.field_list.getModelIds();
} }
this.model_list.loadModels(model_ids).done(
this.model_list.loadModels(model_ids).then(
function(models) { function(models) {
this.model_list.populateModels(models); this.model_list.populateModels(models);
}.bind(this) }.bind(this)

24
bi_view_editor/static/src/xml/bi_view_editor.xml

@ -116,22 +116,20 @@
<li> <li>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input
<input
type="checkbox" type="checkbox"
data-for="column" data-for="column"
class="checkbox-column" class="checkbox-column"
/> Column
</label>
/>
<span>Column</span>
</label>
</div> </div>
</li> </li>
<li> <li>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input
type="checkbox"
data-for="row"
class="checkbox-row"
/> Row
<input type="checkbox" data-for="row" class="checkbox-row" />
<span>Row</span>
</label> </label>
</div> </div>
</li> </li>
@ -142,18 +140,16 @@
type="checkbox" type="checkbox"
data-for="measure" data-for="measure"
class="checkbox-measure" class="checkbox-measure"
/> Measure
/>
<span>Measure</span>
</label> </label>
</div> </div>
</li> </li>
<li> <li>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input
type="checkbox"
data-for="list"
class="checkbox-list"
/> List
<input type="checkbox" data-for="list" class="checkbox-list" />
<span>List</span>
</label> </label>
</div> </div>
</li> </li>

33
bi_view_editor/tests/test_bi_view.py

@ -8,7 +8,7 @@ from odoo.exceptions import UserError, ValidationError
from odoo.tests.common import TransactionCase from odoo.tests.common import TransactionCase
from odoo.tools import mute_logger from odoo.tools import mute_logger
from ..hooks import post_load, uninstall_hook
from ..hooks import uninstall_hook
class TestBiViewEditor(TransactionCase): class TestBiViewEditor(TransactionCase):
@ -174,9 +174,7 @@ class TestBiViewEditor(TransactionCase):
def test_06_create_group_bve_object(self): def test_06_create_group_bve_object(self):
vals = self.bi_view1_vals vals = self.bi_view1_vals
employees_group = self.env.ref("base.group_user") employees_group = self.env.ref("base.group_user")
vals.update(
{"name": "Test View2", "group_ids": [(6, 0, [employees_group.id])],}
)
vals.update({"name": "Test View2", "group_ids": [(6, 0, [employees_group.id])]})
bi_view2 = self.env["bve.view"].create(vals) bi_view2 = self.env["bve.view"].create(vals)
self.assertEqual(len(bi_view2.user_ids), len(employees_group.users)) self.assertEqual(len(bi_view2.user_ids), len(employees_group.users))
@ -200,9 +198,7 @@ class TestBiViewEditor(TransactionCase):
def test_09_create_open_bve_object(self): def test_09_create_open_bve_object(self):
vals = self.bi_view1_vals vals = self.bi_view1_vals
employees_group = self.env.ref("base.group_user") employees_group = self.env.ref("base.group_user")
vals.update(
{"name": "Test View4", "group_ids": [(6, 0, [employees_group.id])],}
)
vals.update({"name": "Test View4", "group_ids": [(6, 0, [employees_group.id])]})
bi_view = self.env["bve.view"].create(vals) bi_view = self.env["bve.view"].create(vals)
self.assertEqual(len(bi_view), 1) self.assertEqual(len(bi_view), 1)
self.assertEqual(len(bi_view.line_ids), 3) self.assertEqual(len(bi_view.line_ids), 3)
@ -251,9 +247,7 @@ class TestBiViewEditor(TransactionCase):
@odoo.tests.tagged("post_install", "-at_install") @odoo.tests.tagged("post_install", "-at_install")
def test_10_create_open_bve_object_apostrophe(self): def test_10_create_open_bve_object_apostrophe(self):
vals = self.bi_view1_vals vals = self.bi_view1_vals
vals.update(
{"name": "Test View5",}
)
vals.update({"name": "Test View5"})
data_list = list() data_list = list()
for r in json.loads(vals["data"]): for r in json.loads(vals["data"]):
r["model_name"] = "model'name" r["model_name"] = "model'name"
@ -310,9 +304,7 @@ class TestBiViewEditor(TransactionCase):
def test_12_check_groups(self): def test_12_check_groups(self):
vals = self.bi_view1_vals vals = self.bi_view1_vals
group_system = self.env.ref("base.group_system") group_system = self.env.ref("base.group_system")
vals.update(
{"name": "Test View1", "group_ids": [(6, 0, [group_system.id])],}
)
vals.update({"name": "Test View1", "group_ids": [(6, 0, [group_system.id])]})
bi_view1 = self.env["bve.view"].create(vals) bi_view1 = self.env["bve.view"].create(vals)
with self.assertRaises(UserError): with self.assertRaises(UserError):
bi_view1.action_create() bi_view1.action_create()
@ -320,9 +312,7 @@ class TestBiViewEditor(TransactionCase):
def test_13_check_lines_missing_model(self): def test_13_check_lines_missing_model(self):
vals = self.bi_view1_vals vals = self.bi_view1_vals
group_user = self.env.ref("base.group_user") group_user = self.env.ref("base.group_user")
vals.update(
{"name": "Test View1", "group_ids": [(6, 0, [group_user.id])],}
)
vals.update({"name": "Test View1", "group_ids": [(6, 0, [group_user.id])]})
bi_view1 = self.env["bve.view"].create(vals) bi_view1 = self.env["bve.view"].create(vals)
for line in bi_view1.line_ids: for line in bi_view1.line_ids:
self.assertTrue(line.model_id) self.assertTrue(line.model_id)
@ -338,9 +328,7 @@ class TestBiViewEditor(TransactionCase):
def test_14_check_lines_missing_fieldl(self): def test_14_check_lines_missing_fieldl(self):
vals = self.bi_view1_vals vals = self.bi_view1_vals
group_user = self.env.ref("base.group_user") group_user = self.env.ref("base.group_user")
vals.update(
{"name": "Test View1", "group_ids": [(6, 0, [group_user.id])],}
)
vals.update({"name": "Test View1", "group_ids": [(6, 0, [group_user.id])]})
bi_view1 = self.env["bve.view"].create(vals) bi_view1 = self.env["bve.view"].create(vals)
for line in bi_view1.line_ids: for line in bi_view1.line_ids:
self.assertTrue(line.field_id) self.assertTrue(line.field_id)
@ -362,9 +350,6 @@ class TestBiViewEditor(TransactionCase):
self.assertTrue(data) self.assertTrue(data)
self.assertTrue(isinstance(data, list)) self.assertTrue(isinstance(data, list))
def test_16_post_load(self):
post_load()
def test_17_uninstall_hook(self): def test_17_uninstall_hook(self):
uninstall_hook(self.cr, self.env) uninstall_hook(self.cr, self.env)
@ -419,9 +404,7 @@ class TestBiViewEditor(TransactionCase):
ERROR: bad_query line in the logs. ERROR: bad_query line in the logs.
""" """
vals = self.bi_view1_vals vals = self.bi_view1_vals
vals.update(
{"name": "Test View broken", "over_condition": "bad SQL code",}
)
vals.update({"name": "Test View broken", "over_condition": "bad SQL code"})
bi_view = self.env["bve.view"].create(vals) bi_view = self.env["bve.view"].create(vals)
with self.assertRaises(UserError) as ue: with self.assertRaises(UserError) as ue:
bi_view.action_create() bi_view.action_create()

18
bi_view_editor/views/bve_view.xml

@ -1,19 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="action_bi_view_editor_translations" model="ir.actions.act_window">
<field name="name">Translations</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.translation</field>
<field name="view_type">form</field>
<field
name="domain"
>[('res_id', '=', active_record.), ('name', '=', 'ir.model.fields,field_description')]</field>
<field name="view_id" ref="base.view_translation_dialog_tree" />
</record>
<record id="view_bi_view_editor_view_tree" model="ir.ui.view"> <record id="view_bi_view_editor_view_tree" model="ir.ui.view">
<field name="model">bve.view</field> <field name="model">bve.view</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Custom BI View">
<tree>
<field name="name" /> <field name="name" />
</tree> </tree>
</field> </field>
@ -21,7 +11,7 @@
<record id="view_bi_view_editor_view_form" model="ir.ui.view"> <record id="view_bi_view_editor_view_form" model="ir.ui.view">
<field name="model">bve.view</field> <field name="model">bve.view</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Custom Object">
<form>
<header> <header>
<button <button
name="action_reset" name="action_reset"
@ -108,6 +98,7 @@
<tree <tree
editable="bottom" editable="bottom"
decoration-muted="in_list == False" decoration-muted="in_list == False"
create="false"
> >
<field name="sequence" widget="handle" /> <field name="sequence" widget="handle" />
<field name="description" string="Field" /> <field name="description" string="Field" />
@ -142,7 +133,7 @@
name="relation_ids" name="relation_ids"
attrs="{'readonly': [('state','=','created')]}" attrs="{'readonly': [('state','=','created')]}"
> >
<tree editable="bottom">
<tree editable="bottom" create="false">
<field name="sequence" widget="handle" /> <field name="sequence" widget="handle" />
<field name="description" string="Field" /> <field name="description" string="Field" />
<field name="model_id" readonly="1" /> <field name="model_id" readonly="1" />
@ -177,7 +168,6 @@
<record id="action_bi_view_editor_view_form" model="ir.actions.act_window"> <record id="action_bi_view_editor_view_form" model="ir.actions.act_window">
<field name="name">Custom BI Views</field> <field name="name">Custom BI Views</field>
<field name="res_model">bve.view</field> <field name="res_model">bve.view</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="help" type="html"> <field name="help" type="html">
<p class="oe_view_nocontent_create"> <p class="oe_view_nocontent_create">

Loading…
Cancel
Save