[FIX]: Remove workflow activity and drop constraint during uninstalling module.
bzr revid: atp@tinyerp.com-20120229135343-g0v04jb5nc723w9q
This commit is contained in:
parent
679d307ead
commit
3465869df7
|
@ -510,7 +510,7 @@ class actions_server(osv.osv):
|
|||
'code':fields.text('Python Code', help="Python code to be executed if condition is met.\n"
|
||||
"It is a Python block that can use the same values as for the condition field"),
|
||||
'sequence': fields.integer('Sequence', help="Important when you deal with multiple actions, the execution order will be decided based on this, low number is higher priority."),
|
||||
'model_id': fields.many2one('ir.model', 'Object', required=True, help="Select the object on which the action will work (read, write, create)."),
|
||||
'model_id': fields.many2one('ir.model', 'Object', required=True, help="Select the object on which the action will work (read, write, create).", ondelete='cascade'),
|
||||
'action_id': fields.many2one('ir.actions.actions', 'Client Action', help="Select the Action Window, Report, Wizard to be executed."),
|
||||
'trigger_name': fields.selection(_select_signals, string='Trigger Signal', size=128, help="The workflow signal to trigger"),
|
||||
'wkf_model_id': fields.many2one('ir.model', 'Target Object', help="The object that should receive the workflow signal (must have an associated workflow)"),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
|
@ -134,11 +135,18 @@ class ir_model(osv.osv):
|
|||
super(ir_model, self).search(cr, uid, domain, limit=limit, context=context),
|
||||
context=context)
|
||||
|
||||
def _drop_table(self, cr, uid, ids, context=None):
|
||||
for model in self.browse(cr, uid, ids, context):
|
||||
model_pool = self.pool.get(model.model)
|
||||
if getattr(model_pool, '_auto', True) and not model.osv_memory:
|
||||
cr.execute("DROP table %s cascade" % model_pool._table)
|
||||
return True
|
||||
|
||||
def unlink(self, cr, user, ids, context=None):
|
||||
for model in self.browse(cr, user, ids, context):
|
||||
if model.state != 'manual':
|
||||
raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(model.name,))
|
||||
# for model in self.browse(cr, user, ids, context):
|
||||
# if model.state != 'manual':
|
||||
# raise except_orm(_('Error'), _("You can not remove the model '%s' !") %(model.name,))
|
||||
# self._drop_table(cr, user, ids, context)
|
||||
res = super(ir_model, self).unlink(cr, user, ids, context)
|
||||
pooler.restart_pool(cr.dbname)
|
||||
return res
|
||||
|
@ -263,17 +271,19 @@ class ir_model_fields(osv.osv):
|
|||
_sql_constraints = [
|
||||
('size_gt_zero', 'CHECK (size>0)',_size_gt_zero_msg ),
|
||||
]
|
||||
|
||||
def _drop_column(self, cr, uid, ids, context=None):
|
||||
for field in self.browse(cr, uid, ids, context):
|
||||
model = self.pool.get(field.model)
|
||||
if not field.model.osv_memory and getattr(model, '_auto', True):
|
||||
cr.execute("ALTER table %s DROP column %s" % (model._table, field.name))
|
||||
model._columns.pop(field.name, None)
|
||||
return True
|
||||
|
||||
def unlink(self, cr, user, ids, context=None):
|
||||
for field in self.browse(cr, user, ids, context):
|
||||
if field.state <> 'manual':
|
||||
raise except_orm(_('Error'), _("You cannot remove the field '%s' !") %(field.name,))
|
||||
#
|
||||
# MAY BE ADD A ALTER TABLE DROP ?
|
||||
#
|
||||
#Removing _columns entry for that table
|
||||
self.pool.get(field.model)._columns.pop(field.name,None)
|
||||
return super(ir_model_fields, self).unlink(cr, user, ids, context)
|
||||
self._drop_column(cr, user, ids, context)
|
||||
res = super(ir_model_fields, self).unlink(cr, user, ids, context)
|
||||
return res
|
||||
|
||||
def create(self, cr, user, vals, context=None):
|
||||
if 'model_id' in vals:
|
||||
|
@ -624,6 +634,7 @@ class ir_model_data(osv.osv):
|
|||
# also stored in pool to avoid being discarded along with this osv instance
|
||||
if getattr(pool, 'model_data_reference_ids', None) is None:
|
||||
self.pool.model_data_reference_ids = {}
|
||||
|
||||
self.loads = self.pool.model_data_reference_ids
|
||||
|
||||
def _auto_init(self, cr, context=None):
|
||||
|
@ -667,9 +678,11 @@ class ir_model_data(osv.osv):
|
|||
except:
|
||||
id = False
|
||||
return id
|
||||
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
""" Regular unlink method, but make sure to clear the caches. """
|
||||
self._pre_process_unlink(cr, uid, ids, context)
|
||||
self._get_id.clear_cache(self)
|
||||
self.get_object_reference.clear_cache(self)
|
||||
return super(ir_model_data,self).unlink(cr, uid, ids, context=context)
|
||||
|
@ -688,7 +701,6 @@ class ir_model_data(osv.osv):
|
|||
if (not xml_id) and (not self.doinit):
|
||||
return False
|
||||
action_id = False
|
||||
|
||||
if xml_id:
|
||||
cr.execute('''SELECT imd.id, imd.res_id, md.id, imd.model
|
||||
FROM ir_model_data imd LEFT JOIN %s md ON (imd.res_id = md.id)
|
||||
|
@ -791,53 +803,78 @@ class ir_model_data(osv.osv):
|
|||
elif xml_id:
|
||||
cr.execute('UPDATE ir_values set value=%s WHERE model=%s and key=%s and name=%s'+where,(value, model, key, name))
|
||||
return True
|
||||
|
||||
def _pre_process_unlink(self, cr, uid, ids, context=None):
|
||||
wkf_todo = []
|
||||
to_unlink = []
|
||||
for data in self.browse(cr, uid, ids, context):
|
||||
model = data.model
|
||||
res_id = data.res_id
|
||||
model_obj = self.pool.get(model)
|
||||
if str(data.name).startswith('constraint_'):
|
||||
cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table,data.name[11:]),)
|
||||
_logger.info('Drop CONSTRAINT %s@%s', data.name[11:], model)
|
||||
continue
|
||||
to_unlink.append((model,res_id))
|
||||
if model=='workflow.activity':
|
||||
cr.execute('select res_type,res_id from wkf_instance where id IN (select inst_id from wkf_workitem where act_id=%s)', (res_id,))
|
||||
wkf_todo.extend(cr.fetchall())
|
||||
cr.execute("update wkf_transition set condition='True', group_id=NULL, signal=NULL,act_to=act_from,act_from=%s where act_to=%s", (res_id,res_id))
|
||||
cr.execute("delete from wkf_transition where act_to=%s", (res_id,))
|
||||
|
||||
for model,res_id in wkf_todo:
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
wf_service.trg_write(uid, model, res_id, cr)
|
||||
|
||||
#cr.commit()
|
||||
if not config.get('import_partial'):
|
||||
for (model, res_id) in to_unlink:
|
||||
if self.pool.get(model):
|
||||
_logger.info('Deleting %s@%s', res_id, model)
|
||||
res_ids = self.pool.get(model).search(cr, uid, [('id', '=', res_id)])
|
||||
if res_ids:
|
||||
self.pool.get(model).unlink(cr, uid, [res_id])
|
||||
cr.commit()
|
||||
# except Exception:
|
||||
# cr.rollback()
|
||||
# _logger.warning(
|
||||
# 'Could not delete obsolete record with id: %d of model %s\n'
|
||||
## 'There should be some relation that points to this resource\n'
|
||||
# 'You should manually fix this and restart with --update=module',
|
||||
# res_id, model)
|
||||
|
||||
def _process_end(self, cr, uid, modules):
|
||||
""" Clear records removed from updated module data.
|
||||
|
||||
This method is called at the end of the module loading process.
|
||||
It is meant to removed records that are no longer present in the
|
||||
updated data. Such records are recognised as the one with an xml id
|
||||
and a module in ir_model_data and noupdate set to false, but not
|
||||
present in self.loads.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
if not modules:
|
||||
return True
|
||||
modules = list(modules)
|
||||
data_ids = self.search(cr, uid, [('module','in',modules)])
|
||||
module_in = ",".join(["%s"] * len(modules))
|
||||
cr.execute('select id,name,model,res_id,module from ir_model_data where module IN (' + module_in + ') and noupdate=%s', modules + [False])
|
||||
wkf_todo = []
|
||||
process_query = 'select id,name,model,res_id,module from ir_model_data where module IN (' + module_in + ')'
|
||||
process_query+= ' and noupdate=%s'
|
||||
to_unlink = []
|
||||
cr.execute( process_query, modules + [False])
|
||||
for (id, name, model, res_id,module) in cr.fetchall():
|
||||
if (module,name) not in self.loads:
|
||||
to_unlink.append((model,res_id))
|
||||
if model=='workflow.activity':
|
||||
cr.execute('select res_type,res_id from wkf_instance where id IN (select inst_id from wkf_workitem where act_id=%s)', (res_id,))
|
||||
wkf_todo.extend(cr.fetchall())
|
||||
cr.execute("update wkf_transition set condition='True', group_id=NULL, signal=NULL,act_to=act_from,act_from=%s where act_to=%s", (res_id,res_id))
|
||||
cr.execute("delete from wkf_transition where act_to=%s", (res_id,))
|
||||
|
||||
for model,id in wkf_todo:
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
wf_service.trg_write(uid, model, id, cr)
|
||||
|
||||
cr.commit()
|
||||
self.pool.get(model).unlink(cr, uid, [res_id])
|
||||
if not config.get('import_partial'):
|
||||
for (model, res_id) in to_unlink:
|
||||
if self.pool.get(model):
|
||||
_logger.info('Deleting %s@%s', res_id, model)
|
||||
try:
|
||||
self.pool.get(model).unlink(cr, uid, [res_id])
|
||||
cr.commit()
|
||||
except Exception:
|
||||
cr.rollback()
|
||||
_logger.warning(
|
||||
'Could not delete obsolete record with id: %d of model %s\n'
|
||||
'There should be some relation that points to this resource\n'
|
||||
'You should manually fix this and restart with --update=module',
|
||||
res_id, model)
|
||||
return True
|
||||
self.pool.get(model).unlink(cr, uid, [res_id])
|
||||
|
||||
# cr.commit()
|
||||
|
||||
|
||||
ir_model_data()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -75,7 +75,7 @@ class ir_rule(osv.osv):
|
|||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=128, select=1),
|
||||
'model_id': fields.many2one('ir.model', 'Object',select=1, required=True),
|
||||
'model_id': fields.many2one('ir.model', 'Object',select=1, required=True, ondelete='cascade'),
|
||||
'global': fields.function(_get_value, string='Global', type='boolean', store=True, help="If no group is specified the rule is global and applied to everyone"),
|
||||
'groups': fields.many2many('res.groups', 'rule_group_rel', 'rule_group_id', 'group_id', 'Groups'),
|
||||
'domain_force': fields.text('Domain'),
|
||||
|
|
|
@ -375,10 +375,18 @@ class module(osv.osv):
|
|||
def button_install_cancel(self, cr, uid, ids, context=None):
|
||||
self.write(cr, uid, ids, {'state': 'uninstalled', 'demo':False})
|
||||
return True
|
||||
|
||||
|
||||
def module_uninstall(self, cr, uid, ids, context=None):
|
||||
model_data = self.pool.get('ir.model.data')
|
||||
remove_modules = map(lambda x: x.name, self.browse(cr, uid, ids, context))
|
||||
data_ids = model_data.search(cr, uid, [('module', 'in', remove_modules)])
|
||||
model_data.unlink(cr, uid, data_ids, context)
|
||||
self.write(cr, uid, ids, {'state': 'uninstalled'})
|
||||
return True
|
||||
|
||||
def button_uninstall(self, cr, uid, ids, context=None):
|
||||
for module in self.browse(cr, uid, ids):
|
||||
cr.execute('''select m.state,m.name
|
||||
cr.execute('''select m.id
|
||||
from
|
||||
ir_module_module_dependency d
|
||||
join
|
||||
|
@ -387,8 +395,11 @@ class module(osv.osv):
|
|||
d.name=%s and
|
||||
m.state not in ('uninstalled','uninstallable','to remove')''', (module.name,))
|
||||
res = cr.fetchall()
|
||||
if res:
|
||||
raise orm.except_orm(_('Error'), _('Some installed modules depend on the module you plan to Uninstall :\n %s') % '\n'.join(map(lambda x: '\t%s: %s' % (x[0], x[1]), res)))
|
||||
for i in range(0,len(res)):
|
||||
ids.append(res[i][0])
|
||||
# if res:
|
||||
# self.write(cr, uid, ids, {'state': 'to remove'})
|
||||
## raise orm.except_orm(_('Error'), _('Some installed modules depend on the module you plan to Uninstall :\n %s') % '\n'.join(map(lambda x: '\t%s: %s' % (x[0], x[1]), res)))
|
||||
self.write(cr, uid, ids, {'state': 'to remove'})
|
||||
return dict(ACTION_DICT, name=_('Uninstall'))
|
||||
|
||||
|
|
|
@ -83,7 +83,9 @@ class base_module_upgrade(osv.osv_memory):
|
|||
|
||||
def upgrade_module(self, cr, uid, ids, context=None):
|
||||
mod_obj = self.pool.get('ir.module.module')
|
||||
ids = mod_obj.search(cr, uid, [('state', 'in', ['to upgrade', 'to remove', 'to install'])])
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
# process to install and upgrade modules
|
||||
ids = mod_obj.search(cr, uid, [('state', 'in', ['to upgrade', 'to install'])])
|
||||
unmet_packages = []
|
||||
mod_dep_obj = self.pool.get('ir.module.module.dependency')
|
||||
for mod in mod_obj.browse(cr, uid, ids):
|
||||
|
@ -95,9 +97,14 @@ class base_module_upgrade(osv.osv_memory):
|
|||
raise osv.except_osv(_('Unmet dependency !'), _('Following modules are not installed or unknown: %s') % ('\n\n' + '\n'.join(unmet_packages)))
|
||||
mod_obj.download(cr, uid, ids, context=context)
|
||||
cr.commit()
|
||||
|
||||
# process to remove modules
|
||||
remove_module_ids = mod_obj.search(cr, uid, [('state', 'in', ['to remove'])])
|
||||
mod_obj.module_uninstall(cr, uid, remove_module_ids, context)
|
||||
|
||||
|
||||
_db, pool = pooler.restart_pool(cr.dbname, update_module=True)
|
||||
|
||||
data_obj = pool.get('ir.model.data')
|
||||
|
||||
id2 = data_obj._get_id(cr, uid, 'base', 'view_base_module_upgrade_install')
|
||||
if id2:
|
||||
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
|
||||
|
|
|
@ -53,7 +53,7 @@ class groups(osv.osv):
|
|||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64, required=True, translate=True),
|
||||
'users': fields.many2many('res.users', 'res_groups_users_rel', 'gid', 'uid', 'Users'),
|
||||
'users': fields.many2many('res.users', 'res_groups_users_rel', 'gid', 'uid', 'Users', ondelete='CASCADE'),
|
||||
'model_access': fields.one2many('ir.model.access', 'group_id', 'Access Controls'),
|
||||
'rule_groups': fields.many2many('ir.rule', 'rule_group_rel',
|
||||
'group_id', 'rule_group_id', 'Rules', domain=[('global', '=', False)]),
|
||||
|
|
|
@ -377,19 +377,22 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
|||
if update_module:
|
||||
# Remove records referenced from ir_model_data for modules to be
|
||||
# removed (and removed the references from ir_model_data).
|
||||
cr.execute("select id,name from ir_module_module where state=%s", ('to remove',))
|
||||
for mod_id, mod_name in cr.fetchall():
|
||||
cr.execute('select model,res_id from ir_model_data where noupdate=%s and module=%s order by id desc', (False, mod_name,))
|
||||
for rmod, rid in cr.fetchall():
|
||||
uid = 1
|
||||
rmod_module= pool.get(rmod)
|
||||
if rmod_module:
|
||||
# TODO group by module so that we can delete multiple ids in a call
|
||||
rmod_module.unlink(cr, uid, [rid])
|
||||
else:
|
||||
_logger.error('Could not locate %s to remove res=%d' % (rmod,rid))
|
||||
cr.execute('delete from ir_model_data where noupdate=%s and module=%s', (False, mod_name,))
|
||||
cr.commit()
|
||||
#cr.execute("select id,name from ir_module_module where state=%s", ('to remove',))
|
||||
#remove_modules = map(lambda x: x['name'], cr.dictfetchall())
|
||||
# Cleanup orphan records
|
||||
#print "pooler", pool.get('mrp.bom')
|
||||
#pool.get('ir.model.data')._process_end(cr, 1, remove_modules, noupdate=None)
|
||||
# for mod_id, mod_name in cr.fetchall():
|
||||
# cr.execute('select model,res_id from ir_model_data where noupdate=%s and module=%s order by id desc', (False, mod_name,))
|
||||
# for rmod, rid in cr.fetchall():
|
||||
# uid = 1
|
||||
# rmod_module= pool.get(rmod)
|
||||
# if rmod_module:
|
||||
# rmod_module.unlink(cr, uid, [rid])
|
||||
# else:
|
||||
# _logger.error('Could not locate %s to remove res=%d' % (rmod,rid))
|
||||
# cr.execute('delete from ir_model_data where module=%s', (mod_name,))
|
||||
# cr.commit()
|
||||
|
||||
# Remove menu items that are not referenced by any of other
|
||||
# (child) menu item, ir_values, or ir_model_data.
|
||||
|
@ -411,8 +414,8 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
|||
_logger.info('removed %d unused menus', cr.rowcount)
|
||||
|
||||
# Pretend that modules to be removed are actually uninstalled.
|
||||
cr.execute("update ir_module_module set state=%s where state=%s", ('uninstalled', 'to remove',))
|
||||
cr.commit()
|
||||
#cr.execute("update ir_module_module set state=%s where state=%s", ('uninstalled', 'to remove',))
|
||||
#cr.commit()
|
||||
|
||||
_logger.info('Modules loaded.')
|
||||
finally:
|
||||
|
|
|
@ -3018,7 +3018,7 @@ class BaseModel(object):
|
|||
|
||||
cr.commit() # start a new transaction
|
||||
|
||||
self._add_sql_constraints(cr)
|
||||
self._add_sql_constraints(cr, context["module"])
|
||||
|
||||
if create:
|
||||
self._execute_sql(cr)
|
||||
|
@ -3145,7 +3145,7 @@ class BaseModel(object):
|
|||
_schema.debug("Create table '%s': m2m relation between '%s' and '%s'", m2m_tbl, self._table, ref)
|
||||
|
||||
|
||||
def _add_sql_constraints(self, cr):
|
||||
def _add_sql_constraints(self, cr, module):
|
||||
"""
|
||||
|
||||
Modify this model's database table constraints so they match the one in
|
||||
|
@ -3196,6 +3196,13 @@ class BaseModel(object):
|
|||
cr.execute(sql_action['query'])
|
||||
cr.commit()
|
||||
_schema.debug(sql_action['msg_ok'])
|
||||
name_id = 'constraint_'+ conname
|
||||
cr.execute('select * from ir_model_data where name=%s and module=%s', (name_id, module))
|
||||
if not cr.rowcount:
|
||||
cr.execute("INSERT INTO ir_model_data (name,date_init,date_update,module, model) VALUES (%s, now(), now(), %s, %s)", \
|
||||
(name_id, module, self._name)
|
||||
)
|
||||
#
|
||||
except:
|
||||
_schema.warning(sql_action['msg_err'])
|
||||
cr.rollback()
|
||||
|
@ -3710,7 +3717,7 @@ class BaseModel(object):
|
|||
wf_service = netsvc.LocalService("workflow")
|
||||
for oid in ids:
|
||||
wf_service.trg_delete(uid, self._name, oid, cr)
|
||||
|
||||
|
||||
|
||||
self.check_access_rule(cr, uid, ids, 'unlink', context=context)
|
||||
pool_model_data = self.pool.get('ir.model.data')
|
||||
|
|
Loading…
Reference in New Issue