product_library adds some fields to product and some utilities addons from OCA

This commit is contained in:
santiky 2021-08-06 13:03:47 +02:00
parent 9145e0cabe
commit 6c8876b991
Signed by: snt
GPG key ID: A9FD34930EADBE71
334 changed files with 92878 additions and 0 deletions

View file

@ -0,0 +1,9 @@
from . import purge_wizard
from . import purge_modules
from . import purge_models
from . import purge_columns
from . import purge_tables
from . import purge_data
from . import purge_menus
from . import create_indexes
from . import purge_properties

View file

@ -0,0 +1,82 @@
# Copyright 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=consider-merging-classes-inherited
from ..identifier_adapter import IdentifierAdapter
from odoo import api, fields, models
class CreateIndexesLine(models.TransientModel):
_inherit = 'cleanup.purge.line'
_name = 'cleanup.create_indexes.line'
purged = fields.Boolean('Created')
wizard_id = fields.Many2one('cleanup.create_indexes.wizard')
field_id = fields.Many2one('ir.model.fields', required=True)
@api.multi
def purge(self):
tables = set()
for field in self.mapped('field_id'):
model = self.env[field.model]
name = '%s_%s_index' % (model._table, field.name)
self.env.cr.execute(
'create index %s ON %s (%s)',
(
IdentifierAdapter(name, quote=False),
IdentifierAdapter(model._table),
IdentifierAdapter(field.name),
),
)
tables.add(model._table)
for table in tables:
self.env.cr.execute(
'analyze %s', (IdentifierAdapter(model._table),)
)
self.write({
'purged': True,
})
class CreateIndexesWizard(models.TransientModel):
_inherit = 'cleanup.purge.wizard'
_name = 'cleanup.create_indexes.wizard'
_description = 'Create indexes'
purge_line_ids = fields.One2many(
'cleanup.create_indexes.line', 'wizard_id',
)
@api.multi
def find(self):
res = list()
for field in self.env['ir.model.fields'].search([
('index', '=', True),
]):
if field.model not in self.env.registry:
continue
model = self.env[field.model]
name = '%s_%s_index' % (model._table, field.name)
self.env.cr.execute(
'select indexname from pg_indexes '
'where indexname=%s and tablename=%s',
(name, model._table)
)
if self.env.cr.rowcount:
continue
self.env.cr.execute(
'select a.attname '
'from pg_attribute a '
'join pg_class c on a.attrelid=c.oid '
'join pg_tables t on t.tablename=c.relname '
'where attname=%s and c.relname=%s',
(field.name, model._table,)
)
if not self.env.cr.rowcount:
continue
res.append((0, 0, {
'name': '%s.%s' % (field.model, field.name),
'field_id': field.id,
}))
return res

View file

@ -0,0 +1,132 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=consider-merging-classes-inherited
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from ..identifier_adapter import IdentifierAdapter
class CleanupPurgeLineColumn(models.TransientModel):
_inherit = 'cleanup.purge.line'
_name = 'cleanup.purge.line.column'
_description = 'Purge Column Wizard Lines'
model_id = fields.Many2one('ir.model', 'Model', required=True,
ondelete='CASCADE')
wizard_id = fields.Many2one(
'cleanup.purge.wizard.column', 'Purge Wizard', readonly=True)
@api.multi
def purge(self):
"""
Unlink columns upon manual confirmation.
"""
if self:
objs = self
else:
objs = self.env['cleanup.purge.line.column']\
.browse(self._context.get('active_ids'))
for line in objs:
if line.purged:
continue
model_pool = self.env[line.model_id.model]
# Check whether the column actually still exists.
# Inheritance such as stock.picking.in from stock.picking
# can lead to double attempts at removal
self.env.cr.execute(
'SELECT count(attname) FROM pg_attribute '
'WHERE attrelid = '
'( SELECT oid FROM pg_class WHERE relname = %s ) '
'AND attname = %s',
(model_pool._table, line.name))
if not self.env.cr.fetchone()[0]:
continue
self.logger.info(
'Dropping column %s from table %s',
line.name, model_pool._table)
self.env.cr.execute(
'ALTER TABLE %s DROP COLUMN %s',
(
IdentifierAdapter(model_pool._table),
IdentifierAdapter(line.name)
))
line.write({'purged': True})
# we need this commit because the ORM will deadlock if
# we still have a pending transaction
self.env.cr.commit() # pylint: disable=invalid-commit
return True
class CleanupPurgeWizardColumn(models.TransientModel):
_inherit = 'cleanup.purge.wizard'
_name = 'cleanup.purge.wizard.column'
_description = 'Purge columns'
# List of known columns in use without corresponding fields
# Format: {table: [fields]}
blacklist = {
'wkf_instance': ['uid'], # lp:1277899
'res_users': ['password', 'password_crypt'],
}
@api.model
def get_orphaned_columns(self, model_pools):
"""
From openobject-server/openerp/osv/orm.py
Iterate on the database columns to identify columns
of fields which have been removed
"""
columns = list(set([
column.name
for model_pool in model_pools
for column in model_pool._fields.values()
if not (column.compute is not None and not column.store)
]))
columns += models.MAGIC_COLUMNS
columns += self.blacklist.get(model_pools[0]._table, [])
self.env.cr.execute(
"SELECT a.attname FROM pg_class c, pg_attribute a "
"WHERE c.relname=%s AND c.oid=a.attrelid AND a.attisdropped=False "
"AND pg_catalog.format_type(a.atttypid, a.atttypmod) "
"NOT IN ('cid', 'tid', 'oid', 'xid') "
"AND a.attname NOT IN %s",
(model_pools[0]._table, tuple(columns)))
return [column for column, in self.env.cr.fetchall()]
@api.model
def find(self):
"""
Search for columns that are not in the corresponding model.
Group models by table to prevent false positives for columns
that are only in some of the models sharing the same table.
Example of this is 'sale_id' not being a field of stock.picking.in
"""
res = []
# mapping of tables to tuples (model id, [pool1, pool2, ...])
table2model = {}
for model in self.env['ir.model'].search([]):
if model.model not in self.env:
continue
model_pool = self.env[model.model]
if not model_pool._auto:
continue
table2model.setdefault(
model_pool._table, (model.id, [])
)[1].append(model_pool)
for table, model_spec in table2model.items():
for column in self.get_orphaned_columns(model_spec[1]):
res.append((0, 0, {
'name': column,
'model_id': model_spec[0]}))
if not res:
raise UserError(_('No orphaned columns found'))
return res
purge_line_ids = fields.One2many(
'cleanup.purge.line.column', 'wizard_id', 'Columns to purge')

View file

@ -0,0 +1,72 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from ..identifier_adapter import IdentifierAdapter
class CleanupPurgeLineData(models.TransientModel):
_inherit = 'cleanup.purge.line'
_name = 'cleanup.purge.line.data'
data_id = fields.Many2one('ir.model.data', 'Data entry')
wizard_id = fields.Many2one(
'cleanup.purge.wizard.data', 'Purge Wizard', readonly=True)
@api.multi
def purge(self):
"""Unlink data entries upon manual confirmation."""
if self:
objs = self
else:
objs = self.env['cleanup.purge.line.data']\
.browse(self._context.get('active_ids'))
to_unlink = objs.filtered(lambda x: not x.purged and x.data_id)
self.logger.info('Purging data entries: %s', to_unlink.mapped('name'))
to_unlink.mapped('data_id').unlink()
return to_unlink.write({'purged': True})
class CleanupPurgeWizardData(models.TransientModel):
_inherit = 'cleanup.purge.wizard'
_name = 'cleanup.purge.wizard.data'
_description = 'Purge data'
@api.model
def find(self):
"""Collect all rows from ir_model_data that refer
to a nonexisting model, or to a nonexisting
row in the model's table."""
res = []
data_ids = []
unknown_models = []
self.env.cr.execute("""SELECT DISTINCT(model) FROM ir_model_data""")
for model, in self.env.cr.fetchall():
if not model:
continue
if model not in self.env:
unknown_models.append(model)
continue
self.env.cr.execute(
"""
SELECT id FROM ir_model_data
WHERE model = %s
AND res_id IS NOT NULL
AND NOT EXISTS (
SELECT id FROM %s WHERE id=ir_model_data.res_id)
""", (model, IdentifierAdapter(self.env[model]._table)))
data_ids.extend(data_row for data_row, in self.env.cr.fetchall())
data_ids += self.env['ir.model.data'].search([
('model', 'in', unknown_models),
]).ids
for data in self.env['ir.model.data'].browse(data_ids):
res.append((0, 0, {
'data_id': data.id,
'name': "%s.%s, object of type %s" % (
data.module, data.name, data.model)}))
if not res:
raise UserError(_('No orphaned data entries found'))
return res
purge_line_ids = fields.One2many(
'cleanup.purge.line.data', 'wizard_id', 'Data to purge')

View file

@ -0,0 +1,58 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=consider-merging-classes-inherited
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class CleanupPurgeLineMenu(models.TransientModel):
_inherit = 'cleanup.purge.line'
_name = 'cleanup.purge.line.menu'
wizard_id = fields.Many2one(
'cleanup.purge.wizard.menu', 'Purge Wizard', readonly=True)
menu_id = fields.Many2one('ir.ui.menu', 'Menu entry')
@api.multi
def purge(self):
"""Unlink menu entries upon manual confirmation."""
if self:
objs = self
else:
objs = self.env['cleanup.purge.line.menu']\
.browse(self._context.get('active_ids'))
to_unlink = objs.filtered(lambda x: not x.purged and x.menu_id)
self.logger.info('Purging menu entries: %s', to_unlink.mapped('name'))
to_unlink.mapped('menu_id').unlink()
return to_unlink.write({'purged': True})
class CleanupPurgeWizardMenu(models.TransientModel):
_inherit = 'cleanup.purge.wizard'
_name = 'cleanup.purge.wizard.menu'
_description = 'Purge menus'
@api.model
def find(self):
"""
Search for models that cannot be instantiated.
"""
res = []
for menu in self.env['ir.ui.menu'].with_context(active_test=False)\
.search([('action', '!=', False)]):
if menu.action.type != 'ir.actions.act_window':
continue
if (menu.action.res_model and menu.action.res_model not in
self.env) or \
(menu.action.src_model and menu.action.src_model not in
self.env):
res.append((0, 0, {
'name': menu.complete_name,
'menu_id': menu.id,
}))
if not res:
raise UserError(_('No dangling menu entries found'))
return res
purge_line_ids = fields.One2many(
'cleanup.purge.line.menu', 'wizard_id', 'Menus to purge')

View file

@ -0,0 +1,124 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=consider-merging-classes-inherited
from odoo import _, api, models, fields
from odoo.exceptions import UserError
from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG
class IrModel(models.Model):
_inherit = 'ir.model'
def _drop_table(self):
"""this function crashes for undefined models"""
existing_model_ids = self.filtered(lambda x: x.model in self.env)
return super(IrModel, existing_model_ids)._drop_table()
@api.depends()
def _inherited_models(self):
"""this function crashes for undefined models"""
existing_model_ids = self.filtered(lambda x: x.model in self.env)
super(IrModel, existing_model_ids)._inherited_models()
class IrModelFields(models.Model):
_inherit = 'ir.model.fields'
@api.multi
def _prepare_update(self):
"""this function crashes for undefined models"""
existing = self.filtered(lambda x: x.model in self.env)
return super(IrModelFields, existing)._prepare_update()
class CleanupPurgeLineModel(models.TransientModel):
_inherit = 'cleanup.purge.line'
_name = 'cleanup.purge.line.model'
_description = 'Purge models'
wizard_id = fields.Many2one(
'cleanup.purge.wizard.model', 'Purge Wizard', readonly=True)
@api.multi
def purge(self):
"""
Unlink models upon manual confirmation.
"""
context_flags = {
MODULE_UNINSTALL_FLAG: True,
'purge': True,
}
if self:
objs = self
else:
objs = self.env['cleanup.purge.line.model']\
.browse(self._context.get('active_ids'))
for line in objs:
self.env.cr.execute(
"SELECT id, model from ir_model WHERE model = %s",
(line.name,))
row = self.env.cr.fetchone()
if not row:
continue
self.logger.info('Purging model %s', row[1])
attachments = self.env['ir.attachment'].search([
('res_model', '=', line.name)
])
if attachments:
self.env.cr.execute(
"UPDATE ir_attachment SET res_model = NULL "
"WHERE id in %s",
(tuple(attachments.ids), ))
self.env['ir.model.constraint'].search([
('model', '=', line.name),
]).unlink()
cronjobs = self.env['ir.cron'].with_context(
active_test=False
).search([
('model_id.model', '=', line.name),
])
if cronjobs:
cronjobs.unlink()
relations = self.env['ir.model.fields'].search([
('relation', '=', row[1]),
]).with_context(**context_flags)
for relation in relations:
try:
# Fails if the model on the target side
# cannot be instantiated
relation.unlink()
except KeyError:
pass
except AttributeError:
pass
self.env['ir.model.relation'].search([
('model', '=', line.name)
]).with_context(**context_flags).unlink()
self.env['ir.model'].browse([row[0]])\
.with_context(**context_flags).unlink()
line.write({'purged': True})
return True
class CleanupPurgeWizardModel(models.TransientModel):
_inherit = 'cleanup.purge.wizard'
_name = 'cleanup.purge.wizard.model'
_description = 'Purge models'
@api.model
def find(self):
"""
Search for models that cannot be instantiated.
"""
res = []
self.env.cr.execute("SELECT model from ir_model")
for model, in self.env.cr.fetchall():
if model not in self.env:
res.append((0, 0, {'name': model}))
if not res:
raise UserError(_('No orphaned models found'))
return res
purge_line_ids = fields.One2many(
'cleanup.purge.line.model', 'wizard_id', 'Models to purge')

View file

@ -0,0 +1,99 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=consider-merging-classes-inherited
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.modules.module import get_module_path
from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG
class IrModelData(models.Model):
_inherit = 'ir.model.data'
@api.model
def _module_data_uninstall(self, modules_to_remove):
"""this function crashes for xmlids on undefined models or fields
referring to undefined models"""
for this in self.search([('module', 'in', modules_to_remove)]):
if this.model == 'ir.model.fields':
field = self.env[this.model].with_context(
**{MODULE_UNINSTALL_FLAG: True}).browse(this.res_id)
if not field.exists() or field.model not in self.env:
this.unlink()
continue
if this.model not in self.env:
this.unlink()
return super(IrModelData, self)._module_data_uninstall(
modules_to_remove)
class CleanupPurgeLineModule(models.TransientModel):
_inherit = 'cleanup.purge.line'
_name = 'cleanup.purge.line.module'
wizard_id = fields.Many2one(
'cleanup.purge.wizard.module', 'Purge Wizard', readonly=True)
@api.multi
def purge(self):
"""
Uninstall modules upon manual confirmation, then reload
the database.
"""
module_names = self.filtered(lambda x: not x.purged).mapped('name')
modules = self.env['ir.module.module'].search([
('name', 'in', module_names)
])
if not modules:
return True
self.logger.info('Purging modules %s', ', '.join(module_names))
modules.filtered(
lambda x: x.state == 'to install'
).write({'state': 'uninstalled'})
modules.filtered(
lambda x: x.state in ('to upgrade', 'to remove')
).write({'state': 'installed'})
modules.filtered(
lambda x: x.state == 'installed' and x.name != 'base'
).button_immediate_uninstall()
modules.refresh()
modules.filtered(
lambda x: x.state not in (
'installed', 'to upgrade', 'to remove', 'to install')
).unlink()
return self.write({'purged': True})
class CleanupPurgeWizardModule(models.TransientModel):
_inherit = 'cleanup.purge.wizard'
_name = 'cleanup.purge.wizard.module'
_description = 'Purge modules'
@api.model
def find(self):
res = []
purge_lines = self.env['cleanup.purge.line.module']
IrModule = self.env['ir.module.module']
for module in IrModule.search(
[
('to_buy', '=', False),
('name', '!=', 'studio_customization')
]
):
if get_module_path(module.name, display_warning=False):
continue
if module.state == 'uninstalled':
purge_lines += self.env['cleanup.purge.line.module'].create({
'name': module.name,
})
continue
res.append((0, 0, {'name': module.name}))
purge_lines.purge()
if not res:
raise UserError(_('No modules found to purge'))
return res
purge_line_ids = fields.One2many(
'cleanup.purge.line.module', 'wizard_id', 'Modules to purge')

View file

@ -0,0 +1,136 @@
# Copyright 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=consider-merging-classes-inherited
from odoo import api, models, fields
REASON_DUPLICATE = 1
REASON_DEFAULT = 2
REASON_DEFAULT_FALSE = 3
REASON_UNKNOWN_MODEL = 4
class CleanupPurgeLineProperty(models.TransientModel):
_inherit = 'cleanup.purge.line'
_name = 'cleanup.purge.line.property'
_description = 'Purge properties'
wizard_id = fields.Many2one(
'cleanup.purge.wizard.property', 'Purge Wizard', readonly=True)
property_id = fields.Many2one('ir.property')
reason = fields.Selection([
(REASON_DUPLICATE, 'Duplicated property'),
(REASON_DEFAULT, 'Same value as default'),
(REASON_DEFAULT_FALSE, 'Empty default property'),
(REASON_UNKNOWN_MODEL, 'Unknown model'),
])
@api.multi
def purge(self):
"""Delete properties"""
self.write({'purged': True})
return self.mapped('property_id').unlink()
class CleanupPurgeWizardProperty(models.TransientModel):
_inherit = 'cleanup.purge.wizard'
_name = 'cleanup.purge.wizard.property'
_description = 'Purge properties'
@api.model
def find(self):
"""
Search property records which are duplicated or the same as the default
"""
result = []
default_properties = self.env['ir.property'].search([
('res_id', '=', False),
])
handled_field_ids = []
for prop in default_properties:
value = None
try:
value = prop.get_by_record()
except KeyError:
result.append({
'name': '%s@%s: %s' % (
prop.name, prop.res_id, value,
),
'property_id': prop.id,
'reason': REASON_UNKNOWN_MODEL,
})
continue
if not value:
result.append({
'name': '%s@%s: %s' % (
prop.name, prop.res_id, value,
),
'property_id': prop.id,
'reason': REASON_DEFAULT_FALSE,
})
continue
if prop.fields_id.id in handled_field_ids:
continue
domain = [
('id', '!=', prop.id),
('fields_id', '=', prop.fields_id.id),
# =? explicitly tests for None or False, not falsyness
('value_float', '=?', prop.value_float or False),
('value_integer', '=?', prop.value_integer or False),
('value_text', '=?', prop.value_text or False),
('value_binary', '=?', prop.value_binary or False),
('value_reference', '=?', prop.value_reference or False),
('value_datetime', '=?', prop.value_datetime or False),
]
if prop.company_id:
domain.append(('company_id', '=', prop.company_id.id))
else:
domain.extend([
'|',
('company_id', '=', False),
(
'company_id', 'in', self.env['res.company'].search([
(
'id', 'not in', default_properties.filtered(
lambda x: x.company_id and
x.fields_id == prop.fields_id
).ids,
)
]).ids
),
])
for redundant_property in self.env['ir.property'].search(domain):
result.append({
'name': '%s@%s: %s' % (
prop.name, redundant_property.res_id,
prop.get_by_record()
),
'property_id': redundant_property.id,
'reason': REASON_DEFAULT,
})
handled_field_ids.append(prop.fields_id.id)
self.env.cr.execute(
'''
with grouped_properties(ids, cnt) as (
select array_agg(id), count(*)
from ir_property group by res_id, company_id, fields_id
)
select ids from grouped_properties where cnt > 1
'''
)
for ids, in self.env.cr.fetchall():
# odoo uses the first property found by search
for prop in self.env['ir.property'].search([
('id', 'in', ids)
])[1:]:
result.append({
'name': '%s@%s: %s' % (
prop.name, prop.res_id, prop.get_by_record()
),
'property_id': prop.id,
'reason': REASON_DUPLICATE,
})
return result
purge_line_ids = fields.One2many(
'cleanup.purge.line.property', 'wizard_id', 'Properties to purge')

View file

@ -0,0 +1,111 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=consider-merging-classes-inherited
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from ..identifier_adapter import IdentifierAdapter
class CleanupPurgeLineTable(models.TransientModel):
_inherit = 'cleanup.purge.line'
_name = 'cleanup.purge.line.table'
_description = 'Purge tables wizard lines'
wizard_id = fields.Many2one(
'cleanup.purge.wizard.table', 'Purge Wizard', readonly=True)
@api.multi
def purge(self):
"""
Unlink tables upon manual confirmation.
"""
if self:
objs = self
else:
objs = self.env['cleanup.purge.line.table']\
.browse(self._context.get('active_ids'))
tables = objs.mapped('name')
for line in objs:
if line.purged:
continue
# Retrieve constraints on the tables to be dropped
# This query is referenced in numerous places
# on the Internet but credits probably go to Tom Lane
# in this post http://www.postgresql.org/\
# message-id/22895.1226088573@sss.pgh.pa.us
# Only using the constraint name and the source table,
# but I'm leaving the rest in for easier debugging
self.env.cr.execute(
"""
SELECT conname, confrelid::regclass, af.attname AS fcol,
conrelid::regclass, a.attname AS col
FROM pg_attribute af, pg_attribute a,
(SELECT conname, conrelid, confrelid,conkey[i] AS conkey,
confkey[i] AS confkey
FROM (select conname, conrelid, confrelid, conkey,
confkey, generate_series(1,array_upper(conkey,1)) AS i
FROM pg_constraint WHERE contype = 'f') ss) ss2
WHERE af.attnum = confkey AND af.attrelid = confrelid AND
a.attnum = conkey AND a.attrelid = conrelid
AND confrelid::regclass = '%s'::regclass;
""", (IdentifierAdapter(line.name, quote=False),))
for constraint in self.env.cr.fetchall():
if constraint[3] in tables:
self.logger.info(
'Dropping constraint %s on table %s (to be dropped)',
constraint[0], constraint[3])
self.env.cr.execute(
"ALTER TABLE %s DROP CONSTRAINT %s",
(
IdentifierAdapter(constraint[3]),
IdentifierAdapter(constraint[0])
))
self.logger.info(
'Dropping table %s', line.name)
self.env.cr.execute(
"DROP TABLE %s", (IdentifierAdapter(line.name),))
line.write({'purged': True})
return True
class CleanupPurgeWizardTable(models.TransientModel):
_inherit = 'cleanup.purge.wizard'
_name = 'cleanup.purge.wizard.table'
_description = 'Purge tables'
@api.model
def find(self):
"""
Search for tables that cannot be instantiated.
Ignore views for now.
"""
known_tables = []
for model in self.env['ir.model'].search([]):
if model.model not in self.env:
continue
model_pool = self.env[model.model]
known_tables.append(model_pool._table)
known_tables += [
column.relation
for column in model_pool._fields.values()
if column.type == 'many2many' and
(column.compute is None or column.store)
and column.relation
]
self.env.cr.execute(
"""
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
AND table_name NOT IN %s""", (tuple(known_tables),))
res = [(0, 0, {'name': row[0]}) for row in self.env.cr.fetchall()]
if not res:
raise UserError(_('No orphaned tables found'))
return res
purge_line_ids = fields.One2many(
'cleanup.purge.line.table', 'wizard_id', 'Tables to purge')

View file

@ -0,0 +1,96 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=consider-merging-classes-inherited
import logging
from odoo import _, api, fields, models
from odoo.exceptions import AccessDenied
class CleanupPurgeLine(models.AbstractModel):
""" Abstract base class for the purge wizard lines """
_name = 'cleanup.purge.line'
_order = 'name'
_description = 'Purge Column Abstract Wizard'
name = fields.Char('Name', readonly=True)
purged = fields.Boolean('Purged', readonly=True)
wizard_id = fields.Many2one('cleanup.purge.wizard')
logger = logging.getLogger('odoo.addons.database_cleanup')
@api.multi
def purge(self):
raise NotImplementedError
@api.model
def create(self, values):
# make sure the user trying this is actually supposed to do it
if self.env.ref(
'base.group_erp_manager') not in self.env.user.groups_id:
raise AccessDenied
return super(CleanupPurgeLine, self).create(values)
class PurgeWizard(models.AbstractModel):
""" Abstract base class for the purge wizards """
_name = 'cleanup.purge.wizard'
_description = 'Purge stuff'
@api.model
def default_get(self, fields_list):
res = super(PurgeWizard, self).default_get(fields_list)
if 'purge_line_ids' in fields_list:
res['purge_line_ids'] = self.find()
return res
@api.multi
def find(self):
raise NotImplementedError
@api.multi
def purge_all(self):
self.mapped('purge_line_ids').purge()
return True
@api.model
def get_wizard_action(self):
wizard = self.create({})
return {
'type': 'ir.actions.act_window',
'name': wizard.display_name,
'views': [(False, 'form')],
'res_model': self._name,
'res_id': wizard.id,
'flags': {
'action_buttons': False,
'sidebar': False,
},
}
@api.multi
def select_lines(self):
return {
'type': 'ir.actions.act_window',
'name': _('Select lines to purge'),
'views': [(False, 'tree'), (False, 'form')],
'res_model': self._fields['purge_line_ids'].comodel_name,
'domain': [('wizard_id', 'in', self.ids)],
}
@api.multi
def name_get(self):
return [
(this.id, self._description)
for this in self
]
@api.model
def create(self, values):
# make sure the user trying this is actually supposed to do it
if self.env.ref(
'base.group_erp_manager') not in self.env.user.groups_id:
raise AccessDenied
return super(PurgeWizard, self).create(values)
purge_line_ids = fields.One2many('cleanup.purge.line', 'wizard_id')