Drop bi views when uninstalling module
parent
f7a750acad
commit
205433abb1
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
from . import wizard
|
from . import wizard
|
||||||
from .hooks import uninstall_hook
|
from .hooks import post_load, uninstall_hook
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
'qweb': [
|
'qweb': [
|
||||||
'static/src/xml/bi_view_editor.xml'
|
'static/src/xml/bi_view_editor.xml'
|
||||||
],
|
],
|
||||||
|
'post_load': 'post_load',
|
||||||
|
'uninstall_hook': 'uninstall_hook',
|
||||||
'installable': True,
|
'installable': True,
|
||||||
'uninstall_hook': 'uninstall_hook'
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,56 @@
|
||||||
# Copyright 2015-2018 Onestein (<http://www.onestein.eu>)
|
# Copyright 2015-2018 Onestein (<http://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
|
||||||
|
from odoo import api, modules
|
||||||
|
|
||||||
|
from odoo.tools import existing_tables, topological_sort
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _bi_view(_name):
|
||||||
|
return _name[0:6] == '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
|
||||||
|
@ -11,3 +61,12 @@ def uninstall_hook(cr, registry):
|
||||||
cr.execute("""
|
cr.execute("""
|
||||||
delete from bve_view where model_name like 'x_bve.%'
|
delete from bve_view where model_name like 'x_bve.%'
|
||||||
""")
|
""")
|
||||||
|
cr.execute("""
|
||||||
|
SELECT 'DROP VIEW ' || table_name
|
||||||
|
FROM information_schema.views
|
||||||
|
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
|
||||||
|
AND table_name like 'x_bve_%'
|
||||||
|
""")
|
||||||
|
results = list(cr.fetchall())
|
||||||
|
for result in results:
|
||||||
|
cr.execute(result[0])
|
||||||
|
|
|
@ -270,7 +270,7 @@ class IrModel(models.Model):
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def create(self, vals):
|
def create(self, vals):
|
||||||
if self._context and self._context.get('bve'):
|
if self.env.context and self.env.context.get('bve'):
|
||||||
vals['state'] = 'base'
|
vals['state'] = 'base'
|
||||||
res = super(IrModel, self).create(vals)
|
res = super(IrModel, self).create(vals)
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ class IrModel(models.Model):
|
||||||
self.env.cr.execute(q, (res.id, ))
|
self.env.cr.execute(q, (res.id, ))
|
||||||
|
|
||||||
# # update registry
|
# # update registry
|
||||||
if self._context.get('bve'):
|
if self.env.context.get('bve'):
|
||||||
# setup models; this reloads custom models in registry
|
# setup models; this reloads custom models in registry
|
||||||
self.pool.setup_models(self._cr)
|
self.pool.setup_models(self._cr)
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,9 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from odoo import SUPERUSER_ID
|
from odoo import _, api, models
|
||||||
from odoo import _, api, models, modules, tools
|
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
from odoo.tools import (existing_tables, topological_sort)
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,122 +14,22 @@ def _bi_view(_name):
|
||||||
return _name[0:6] == 'x_bve.'
|
return _name[0:6] == 'x_bve.'
|
||||||
|
|
||||||
|
|
||||||
def check_tables_exist(self, cr):
|
_auto_init_orig = models.BaseModel._auto_init
|
||||||
"""
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
@api.model_cr_context
|
@api.model_cr_context
|
||||||
def _auto_init(self):
|
def _auto_init(self):
|
||||||
""" Initialize the database schema of ``self``:
|
|
||||||
- create the corresponding table,
|
|
||||||
- create/update the necessary columns/tables for fields,
|
|
||||||
- initialize new columns on existing rows,
|
|
||||||
- add the SQL constraints given on the model,
|
|
||||||
- add the indexes on indexed fields,
|
|
||||||
|
|
||||||
Also prepare post-init stuff to:
|
|
||||||
- add foreign key constraints,
|
|
||||||
- reflect models, fields, relations and constraints,
|
|
||||||
- mark fields to recompute on existing records.
|
|
||||||
|
|
||||||
Note: you should not override this method. Instead, you can modify
|
|
||||||
the model's database schema by overriding method :meth:`~.init`,
|
|
||||||
which is called right after this one.
|
|
||||||
"""
|
|
||||||
# This monkey patch is meant to fix an error (probably
|
# This monkey patch is meant to fix an error (probably
|
||||||
# introduced by https://github.com/odoo/odoo/pull/15412), while
|
# introduced by https://github.com/odoo/odoo/pull/15412), while
|
||||||
# running an update all. The _auto_init() method invoked during
|
# running an update all. The _auto_init() method invoked during
|
||||||
# an update all is the one of BaseModel, and not the one of Base.
|
# an update all is the one of BaseModel, and not the one of Base.
|
||||||
|
|
||||||
# START OF patch
|
# This monkey patch seems not working if defined inside the post_load()
|
||||||
|
|
||||||
if _bi_view(self._name):
|
if _bi_view(self._name):
|
||||||
return
|
return
|
||||||
# END of patch
|
return _auto_init_orig(self)
|
||||||
|
|
||||||
models.raise_on_invalid_object_name(self._name)
|
|
||||||
|
|
||||||
# This prevents anything called by this method (in particular default
|
|
||||||
# values) from prefetching a field for which the corresponding column
|
|
||||||
# has not been added in database yet!
|
|
||||||
self = self.with_context(prefetch_fields=False)
|
|
||||||
|
|
||||||
self.pool.post_init(self._reflect)
|
|
||||||
|
|
||||||
cr = self._cr
|
|
||||||
parent_store_compute = False
|
|
||||||
update_custom_fields = self._context.get('update_custom_fields', False)
|
|
||||||
must_create_table = not tools.table_exists(cr, self._table)
|
|
||||||
|
|
||||||
if self._auto:
|
|
||||||
if must_create_table:
|
|
||||||
tools.create_model_table(cr, self._table, self._description)
|
|
||||||
|
|
||||||
if self._parent_store:
|
|
||||||
if not tools.column_exists(cr, self._table, 'parent_left'):
|
|
||||||
self._create_parent_columns()
|
|
||||||
parent_store_compute = True
|
|
||||||
|
|
||||||
self._check_removed_columns(log=False)
|
|
||||||
|
|
||||||
# update the database schema for fields
|
|
||||||
columns = tools.table_columns(cr, self._table)
|
|
||||||
|
|
||||||
def recompute(field):
|
|
||||||
_logger.info("Storing computed values of %s", field)
|
|
||||||
recs = self.with_context(active_test=False).search([])
|
|
||||||
recs._recompute_todo(field)
|
|
||||||
|
|
||||||
for field in self._fields.values():
|
|
||||||
if not field.store:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if field.manual and not update_custom_fields:
|
|
||||||
continue # don't update custom fields
|
|
||||||
|
|
||||||
new = field.update_db(self, columns)
|
|
||||||
if new and field.compute:
|
|
||||||
self.pool.post_init(recompute, field)
|
|
||||||
|
|
||||||
if self._auto:
|
|
||||||
self._add_sql_constraints()
|
|
||||||
|
|
||||||
if must_create_table:
|
|
||||||
self._execute_sql()
|
|
||||||
|
|
||||||
if parent_store_compute:
|
|
||||||
self._parent_store_compute()
|
|
||||||
|
|
||||||
|
|
||||||
models.BaseModel._auto_init = _auto_init
|
models.BaseModel._auto_init = _auto_init
|
||||||
|
@ -141,11 +38,6 @@ models.BaseModel._auto_init = _auto_init
|
||||||
class Base(models.AbstractModel):
|
class Base(models.AbstractModel):
|
||||||
_inherit = 'base'
|
_inherit = 'base'
|
||||||
|
|
||||||
@api.model
|
|
||||||
def _auto_init(self):
|
|
||||||
if not _bi_view(self._name):
|
|
||||||
super(Base, self)._auto_init()
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _setup_complete(self):
|
def _setup_complete(self):
|
||||||
if not _bi_view(self._name):
|
if not _bi_view(self._name):
|
||||||
|
|
|
@ -14,7 +14,7 @@ odoo.define('bi_view_editor.JoinNodeDialog', function (require) {
|
||||||
'/bi_view_editor/static/src/xml/bi_view_editor.xml'
|
'/bi_view_editor/static/src/xml/bi_view_editor.xml'
|
||||||
]),
|
]),
|
||||||
events: {
|
events: {
|
||||||
"click li": "choiceClicked",
|
"click li": "choiceClicked"
|
||||||
},
|
},
|
||||||
init: function (parent, options, choices, model_data) {
|
init: function (parent, options, choices, model_data) {
|
||||||
this.choices = choices;
|
this.choices = choices;
|
||||||
|
@ -36,7 +36,7 @@ odoo.define('bi_view_editor.JoinNodeDialog', function (require) {
|
||||||
text: _t("Cancel"),
|
text: _t("Cancel"),
|
||||||
classes: "btn-default o_form_button_cancel",
|
classes: "btn-default o_form_button_cancel",
|
||||||
close: true
|
close: true
|
||||||
}],
|
}]
|
||||||
});
|
});
|
||||||
this._super(parent, defaults);
|
this._super(parent, defaults);
|
||||||
},
|
},
|
||||||
|
|
|
@ -239,11 +239,11 @@ class TestBiViewEditor(TransactionCase):
|
||||||
'name': "Test View5",
|
'name': "Test View5",
|
||||||
'group_ids': [(6, 0, [employees_group.id])],
|
'group_ids': [(6, 0, [employees_group.id])],
|
||||||
})
|
})
|
||||||
l = 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"
|
||||||
l.append(r)
|
data_list.append(r)
|
||||||
new_format_data = json.dumps(l)
|
new_format_data = json.dumps(data_list)
|
||||||
vals.update({'data': new_format_data})
|
vals.update({'data': new_format_data})
|
||||||
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)
|
||||||
|
|
|
@ -9,9 +9,9 @@ class WizardModelMenuCreate(models.TransientModel):
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def menu_create(self):
|
def menu_create(self):
|
||||||
if self._context.get('active_model') == 'bve.view':
|
if self.env.context.get('active_model') == 'bve.view':
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
active_id = self._context.get('active_id')
|
active_id = self.env.context.get('active_id')
|
||||||
bve_view = self.env['bve.view'].browse(active_id)
|
bve_view = self.env['bve.view'].browse(active_id)
|
||||||
menu = self.env['ir.ui.menu'].create({
|
menu = self.env['ir.ui.menu'].create({
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
|
@ -31,8 +31,8 @@ class WizardModelMenuCreate(models.TransientModel):
|
||||||
@api.model
|
@api.model
|
||||||
def default_get(self, fields_list):
|
def default_get(self, fields_list):
|
||||||
defaults = super(WizardModelMenuCreate, self).default_get(fields_list)
|
defaults = super(WizardModelMenuCreate, self).default_get(fields_list)
|
||||||
if self._context.get('active_model') == 'bve.view':
|
if self.env.context.get('active_model') == 'bve.view':
|
||||||
active_id = self._context.get('active_id')
|
active_id = self.env.context.get('active_id')
|
||||||
bve_view = self.env['bve.view'].browse(active_id)
|
bve_view = self.env['bve.view'].browse(active_id)
|
||||||
defaults.setdefault('name', bve_view.name)
|
defaults.setdefault('name', bve_view.name)
|
||||||
return defaults
|
return defaults
|
||||||
|
|
Loading…
Reference in New Issue