From 3465869df7bd1b847a08a5e3ef76e28bb174b610 Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Wed, 29 Feb 2012 19:23:43 +0530 Subject: [PATCH 01/24] [FIX]: Remove workflow activity and drop constraint during uninstalling module. bzr revid: atp@tinyerp.com-20120229135343-g0v04jb5nc723w9q --- openerp/addons/base/ir/ir_actions.py | 2 +- openerp/addons/base/ir/ir_model.py | 117 ++++++++++++------ openerp/addons/base/ir/ir_rule.py | 2 +- openerp/addons/base/module/module.py | 19 ++- .../base/module/wizard/base_module_upgrade.py | 13 +- openerp/addons/base/res/res_users.py | 2 +- openerp/modules/loading.py | 33 ++--- openerp/osv/orm.py | 13 +- 8 files changed, 133 insertions(+), 68 deletions(-) diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index 236c6af7119..db3c7fcdbae 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -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)"), diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index e8ce3adb592..012bf2028d1 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -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: diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index 0626b2b9c1e..227f0eb32b9 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -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'), diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index beb35ee38b2..328afef76aa 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -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')) diff --git a/openerp/addons/base/module/wizard/base_module_upgrade.py b/openerp/addons/base/module/wizard/base_module_upgrade.py index 3b8671b0ebb..5e7b82d241f 100644 --- a/openerp/addons/base/module/wizard/base_module_upgrade.py +++ b/openerp/addons/base/module/wizard/base_module_upgrade.py @@ -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 diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index f148813ae05..b196cb862d1 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -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)]), diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index b3f831f9709..66ed210ccc7 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -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: diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 8901cf5ed87..fae53bd9abc 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -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') From 9d8b51afc39763529765c5c7ff5af8a740c61350 Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Thu, 1 Mar 2012 09:44:44 +0530 Subject: [PATCH 02/24] [FIX]: remove unused code bzr revid: atp@tinyerp.com-20120301041444-jksnjci0ozaly28a --- openerp/addons/base/ir/ir_actions.py | 2 +- openerp/addons/base/ir/ir_model.py | 3 +-- openerp/addons/base/ir/ir_rule.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index db3c7fcdbae..236c6af7119 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -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).", ondelete='cascade'), + 'model_id': fields.many2one('ir.model', 'Object', required=True, help="Select the object on which the action will work (read, write, create)."), '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)"), diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 012bf2028d1..a85c83e07d6 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -861,11 +861,10 @@ class ir_model_data(osv.osv): 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]) + 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)) - 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): diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index 227f0eb32b9..0626b2b9c1e 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -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, ondelete='cascade'), + 'model_id': fields.many2one('ir.model', 'Object',select=1, required=True), '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'), From c86917ea38bb6b3be8fd1a43ec4fd15af02e3179 Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Thu, 1 Mar 2012 09:57:45 +0530 Subject: [PATCH 03/24] [ADD]: Add ondelete cascade for ir_act_Server bzr revid: atp@tinyerp.com-20120301042745-v5wn3owi6f8cq505 --- openerp/addons/base/ir/ir_actions.py | 2 +- openerp/addons/base/ir/ir_rule.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index 236c6af7119..db3c7fcdbae 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -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)"), diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index 0626b2b9c1e..227f0eb32b9 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -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'), From 180a23c7ccf702668dd65ad456b8f23792d14206 Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Fri, 9 Mar 2012 18:17:53 +0530 Subject: [PATCH 04/24] [FIX]: uninstall module. Remove foreign key references. Remove sql constraint . Remove workflow activity and transition based on deleted cascade. Drop ir model fields columns and drop table. bzr revid: atp@tinyerp.com-20120309124753-c4yzeoij5p2fmhgg --- openerp/addons/base/ir/ir_model.py | 130 ++++++++++++------ openerp/addons/base/ir/workflow/workflow.py | 2 +- openerp/addons/base/module/module.py | 10 +- .../base/module/wizard/base_module_upgrade.py | 2 - openerp/addons/base/res/res_users.py | 15 -- openerp/modules/loading.py | 31 ++--- openerp/osv/orm.py | 24 +++- 7 files changed, 132 insertions(+), 82 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index a85c83e07d6..f838a6a4f7a 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -138,15 +138,21 @@ class ir_model(osv.osv): 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) + # this test should be removed, but check if drop view instead of drop table + # just check if table or view exists + cr.execute("select relkind from pg_class where relname=%s", (model_pool._table,)) + result = cr.fetchone() + if result and result[0] == 'v': + cr.execute("DROP view %s" % (model_pool._table,)) + elif result and result[0] == 'r': + cr.execute("DROP TABLE %s" % (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,)) - # self._drop_table(cr, user, ids, context) + self._drop_table(cr, user, ids, context) res = super(ir_model, self).unlink(cr, user, ids, context) pooler.restart_pool(cr.dbname) return res @@ -273,11 +279,15 @@ class ir_model_fields(osv.osv): ] 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) + field = self.browse(cr, uid, ids, context) + model = self.pool.get(field.model) + cr.execute("select relkind from pg_class where relname=%s", (model._table,)) + result = cr.fetchone()[0] + cr.execute("SELECT column_name FROM information_schema.columns WHERE table_name ='%s'and column_name='%s'"%(model._table, field.name)) + column_name = cr.fetchone() + if column_name and result == 'r': + cr.execute("ALTER table %s DROP column %s cascade" % (model._table, field.name)) + model._columns.pop(field.name, None) return True def unlink(self, cr, user, ids, context=None): @@ -630,7 +640,6 @@ class ir_model_data(osv.osv): def __init__(self, pool, cr): osv.osv.__init__(self, pool, cr) self.doinit = True - # 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 = {} @@ -682,7 +691,6 @@ class ir_model_data(osv.osv): 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) @@ -691,10 +699,8 @@ class ir_model_data(osv.osv): model_obj = self.pool.get(model) if not context: context = {} - # records created during module install should result in res.log entries that are already read! context = dict(context, res_log_read=True) - if xml_id and ('.' in xml_id): assert len(xml_id.split('.'))==2, _("'%s' contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id") % (xml_id) module, xml_id = xml_id.split('.') @@ -807,41 +813,90 @@ class ir_model_data(osv.osv): def _pre_process_unlink(self, cr, uid, ids, context=None): wkf_todo = [] to_unlink = [] + to_drop_table = [] + ids.sort() + ids.reverse() 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) + name = data.name + if str(name).startswith('foreign_key_'): + name = name[12:] + # test if constraint exists + cr.execute('select conname from pg_constraint where contype=%s and conname=%s',('f', name),) + if cr.fetchall(): + cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model,name),) + _logger.info('Drop CONSTRAINT %s@%s', name, model) continue - to_unlink.append((model,res_id)) + + if str(name).startswith('table_'): + cr.execute("SELECT table_name FROM information_schema.tables WHERE table_name='%s'"%(name[6:])) + column_name = cr.fetchone() + if column_name: + to_drop_table.append(name[6:]) + continue + + if str(name).startswith('constraint_'): + # test if constraint exists + cr.execute('select conname from pg_constraint where contype=%s and conname=%s',('u', name),) + if cr.fetchall(): + cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table,name[11:]),) + _logger.info('Drop CONSTRAINT %s@%s', 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) + try: + wf_service.trg_write(uid, model, res_id, cr) + except: + _logger.info('Unable to process workflow %s@%s', res_id, model) - #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) + # drop relation .table + for model in to_drop_table: + cr.execute('DROP TABLE %s cascade'% (model),) + _logger.info('Dropping table %s', model) + + for (model, res_id) in to_unlink: + if model in ('ir.model','ir.model.fields', 'ir.model.data'): + continue + model_ids = self.search(cr, uid, [('model', '=', model),('res_id', '=', res_id)]) + if len(model_ids) > 1: + # if others module have defined this record, we do not delete it + continue + _logger.info('Deleting %s@%s', res_id, model) + try: + self.pool.get(model).unlink(cr, uid, res_id) + except: + _logger.info('Unable to delete %s@%s', res_id, model) + cr.commit() + + for (model, res_id) in to_unlink: + if model not in ('ir.model.fields',): + continue + model_ids = self.search(cr, uid, [('model', '=', model),('res_id', '=', res_id)]) + if len(model_ids) > 1: + # if others module have defined this record, we do not delete it + continue + _logger.info('Deleting %s@%s', res_id, model) + self.pool.get(model).unlink(cr, uid, res_id) + + for (model, res_id) in to_unlink: + if model not in ('ir.model',): + continue + model_ids = self.search(cr, uid, [('model', '=', model),('res_id', '=', res_id)]) + if len(model_ids) > 1: + # if others module have defined this record, we do not delete it + continue + _logger.info('Deleting %s@%s', res_id, model) + self.pool.get(model).unlink(cr, uid, [res_id]) + cr.commit() def _process_end(self, cr, uid, modules): """ Clear records removed from updated module data. @@ -851,8 +906,6 @@ class ir_model_data(osv.osv): 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) @@ -871,9 +924,6 @@ class ir_model_data(osv.osv): _logger.info('Deleting %s@%s', res_id, model) self.pool.get(model).unlink(cr, uid, [res_id]) - # cr.commit() - - ir_model_data() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/workflow/workflow.py b/openerp/addons/base/ir/workflow/workflow.py index edd070ae50d..8ec843230d4 100644 --- a/openerp/addons/base/ir/workflow/workflow.py +++ b/openerp/addons/base/ir/workflow/workflow.py @@ -194,7 +194,7 @@ class wkf_workitem(osv.osv): _log_access = False _rec_name = 'state' _columns = { - 'act_id': fields.many2one('workflow.activity', 'Activity', required=True, ondelete="restrict", select=True), + 'act_id': fields.many2one('workflow.activity', 'Activity', required=True, ondelete="cascade", select=True), 'wkf_id': fields.related('act_id','wkf_id', type='many2one', relation='workflow', string='Workflow'), 'subflow_id': fields.many2one('workflow.instance', 'Subflow', ondelete="cascade", select=True), 'inst_id': fields.many2one('workflow.instance', 'Instance', required=True, ondelete="cascade", select=True), diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index 328afef76aa..d6732681fb2 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -343,7 +343,6 @@ class module(osv.osv): # Mark them to be installed. if to_install_ids: self.button_install(cr, uid, to_install_ids, context=context) - return dict(ACTION_DICT, name=_('Install')) def button_immediate_install(self, cr, uid, ids, context=None): @@ -377,11 +376,20 @@ class module(osv.osv): return True def module_uninstall(self, cr, uid, ids, context=None): + + # you have to uninstall in the right order, not all modules at the same time + 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._pre_process_unlink(cr, uid, data_ids, context) model_data.unlink(cr, uid, data_ids, context) + self.write(cr, uid, ids, {'state': 'uninstalled'}) + + # should we call process_end istead of loading, or both ? return True def button_uninstall(self, cr, uid, ids, context=None): diff --git a/openerp/addons/base/module/wizard/base_module_upgrade.py b/openerp/addons/base/module/wizard/base_module_upgrade.py index 5e7b82d241f..f19decf4c3e 100644 --- a/openerp/addons/base/module/wizard/base_module_upgrade.py +++ b/openerp/addons/base/module/wizard/base_module_upgrade.py @@ -97,12 +97,10 @@ 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) id2 = data_obj._get_id(cr, uid, 'base', 'view_base_module_upgrade_install') diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index b196cb862d1..e7264b10d79 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -107,21 +107,6 @@ class groups(osv.osv): aid.write({'groups_id': [(4, gid)]}) return gid - def unlink(self, cr, uid, ids, context=None): - group_users = [] - for record in self.read(cr, uid, ids, ['users'], context=context): - if record['users']: - group_users.extend(record['users']) - if group_users: - user_names = [user.name for user in self.pool.get('res.users').browse(cr, uid, group_users, context=context)] - user_names = list(set(user_names)) - if len(user_names) >= 5: - user_names = user_names[:5] + ['...'] - raise osv.except_osv(_('Warning !'), - _('Group(s) cannot be deleted, because some user(s) still belong to them: %s !') % \ - ', '.join(user_names)) - return super(groups, self).unlink(cr, uid, ids, context=context) - def get_extended_interface_group(self, cr, uid, context=None): data_obj = self.pool.get('ir.model.data') extended_group_data_id = data_obj._get_id(cr, uid, 'base', 'group_extended') diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index 66ed210ccc7..1ec39ab545d 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -374,13 +374,12 @@ def load_modules(db, force_demo=False, status=None, update_module=False): tools.config[kind] = {} cr.commit() - if update_module: +# 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',)) #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,)) @@ -398,20 +397,20 @@ def load_modules(db, force_demo=False, status=None, update_module=False): # (child) menu item, ir_values, or ir_model_data. # This code could be a method of ir_ui_menu. # TODO: remove menu without actions of children - while True: - cr.execute('''delete from - ir_ui_menu - where - (id not IN (select parent_id from ir_ui_menu where parent_id is not null)) - and - (id not IN (select res_id from ir_values where model='ir.ui.menu')) - and - (id not IN (select res_id from ir_model_data where model='ir.ui.menu'))''') - cr.commit() - if not cr.rowcount: - break - else: - _logger.info('removed %d unused menus', cr.rowcount) +# while True: +# cr.execute('''delete from +# ir_ui_menu +# where +# (id not IN (select parent_id from ir_ui_menu where parent_id is not null)) +# and +# (id not IN (select res_id from ir_values where model='ir.ui.menu')) +# and +# (id not IN (select res_id from ir_model_data where model='ir.ui.menu'))''') +# cr.commit() +# if not cr.rowcount: +# break +# else: +# _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',)) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index fae53bd9abc..40a4f4183ff 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -904,6 +904,7 @@ class BaseModel(object): # If new class defines a constraint with # same function name, we let it override # the old one. + new[c2] = c exist = True break @@ -2760,7 +2761,6 @@ class BaseModel(object): update_custom_fields = context.get('update_custom_fields', False) self._field_create(cr, context=context) create = not self._table_exist(cr) - if getattr(self, '_auto', True): if create: @@ -3029,11 +3029,16 @@ class BaseModel(object): return todo_end - def _auto_end(self, cr, context=None): """ Create the foreign keys recorded by _auto_init. """ for t, k, r, d in self._foreign_keys: cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY ("%s") REFERENCES "%s" ON DELETE %s' % (t, k, r, d)) + name_id = "foreign_key_"+t+"_"+k+"_fkey" + cr.execute('select * from ir_model_data where name=%s and module=%s', (name_id, self._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, self._module, t) + ) cr.commit() del self._foreign_keys @@ -3112,6 +3117,7 @@ class BaseModel(object): def _o2m_raise_on_missing_reference(self, cr, f): # TODO this check should be a method on fields.one2many. + other = self.pool.get(f._obj) if other: # TODO the condition could use fields_get_keys(). @@ -3119,7 +3125,6 @@ class BaseModel(object): if f._fields_id not in other._inherit_fields.keys(): raise except_orm('Programming Error', ("There is no reference field '%s' found for '%s'") % (f._fields_id, f._obj,)) - def _m2m_raise_or_create_relation(self, cr, f): m2m_tbl, col1, col2 = f._sql_names(self) cr.execute("SELECT relname FROM pg_class WHERE relkind IN ('r','v') AND relname=%s", (m2m_tbl,)) @@ -3129,7 +3134,14 @@ class BaseModel(object): dest_model = self.pool.get(f._obj) ref = dest_model._table cr.execute('CREATE TABLE "%s" ("%s" INTEGER NOT NULL, "%s" INTEGER NOT NULL, UNIQUE("%s","%s")) WITH OIDS' % (m2m_tbl, col1, col2, col1, col2)) - + #create many2many references + name_id = 'table_'+m2m_tbl + cr.execute('select * from ir_model_data where name=%s and module=%s', (name_id, self._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, self._module, self._name) + ) + # self.pool.get('ir.model.data')._update(cr, 1, self._name, self._module, {}, 'table_'+m2m_tbl, store=True, noupdate=False, mode='init', res_id=False, context=None) # create foreign key references with ondelete=cascade, unless the targets are SQL views cr.execute("SELECT relkind FROM pg_class WHERE relkind IN ('v') AND relname=%s", (ref,)) if not cr.fetchall(): @@ -3157,7 +3169,6 @@ class BaseModel(object): cr.execute("SELECT conname, pg_catalog.pg_get_constraintdef(oid, true) as condef FROM pg_constraint where conname=%s", (conname,)) existing_constraints = cr.dictfetchall() - sql_actions = { 'drop': { 'execute': False, @@ -3198,11 +3209,10 @@ class BaseModel(object): _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: + 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() From 4d3849b108f627a565584d9a209944586e8d2b0d Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Mon, 12 Mar 2012 12:34:45 +0530 Subject: [PATCH 05/24] [FIX]: Minor fix for null value in fetchall bzr revid: atp@tinyerp.com-20120312070445-t9u9dowz5j2mhzmd --- openerp/addons/base/ir/ir_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index f838a6a4f7a..fd000f55432 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -282,10 +282,10 @@ class ir_model_fields(osv.osv): field = self.browse(cr, uid, ids, context) model = self.pool.get(field.model) cr.execute("select relkind from pg_class where relname=%s", (model._table,)) - result = cr.fetchone()[0] + result = cr.fetchone() cr.execute("SELECT column_name FROM information_schema.columns WHERE table_name ='%s'and column_name='%s'"%(model._table, field.name)) column_name = cr.fetchone() - if column_name and result == 'r': + if column_name and (result and result[0] == 'r'): cr.execute("ALTER table %s DROP column %s cascade" % (model._table, field.name)) model._columns.pop(field.name, None) return True From 7cf78f08db0dd0d1995c2cd9b411b58ffaab494b Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Mon, 12 Mar 2012 14:12:17 +0530 Subject: [PATCH 06/24] [FIX]: FIX query groupby problem for string bzr revid: atp@tinyerp.com-20120312084217-jixwo97b30qht158 --- openerp/addons/base/ir/ir_model.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index fd000f55432..a344c1a3885 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -140,12 +140,12 @@ class ir_model(osv.osv): model_pool = self.pool.get(model.model) # this test should be removed, but check if drop view instead of drop table # just check if table or view exists - cr.execute("select relkind from pg_class where relname=%s", (model_pool._table,)) + cr.execute('select relkind from pg_class where relname=%s', (model_pool._table,)) result = cr.fetchone() if result and result[0] == 'v': - cr.execute("DROP view %s" % (model_pool._table,)) + cr.execute('DROP view %s' % (model_pool._table,)) elif result and result[0] == 'r': - cr.execute("DROP TABLE %s" % (model_pool._table,)) + cr.execute('DROP TABLE %s' % (model_pool._table,)) return True def unlink(self, cr, user, ids, context=None): @@ -281,12 +281,12 @@ class ir_model_fields(osv.osv): def _drop_column(self, cr, uid, ids, context=None): field = self.browse(cr, uid, ids, context) model = self.pool.get(field.model) - cr.execute("select relkind from pg_class where relname=%s", (model._table,)) + cr.execute('select relkind from pg_class where relname=%s', (model._table,)) result = cr.fetchone() - cr.execute("SELECT column_name FROM information_schema.columns WHERE table_name ='%s'and column_name='%s'"%(model._table, field.name)) + cr.execute("SELECT column_name FROM information_schema.columns WHERE table_name ='%s' and column_name='%s'" %(model._table, field.name)) column_name = cr.fetchone() if column_name and (result and result[0] == 'r'): - cr.execute("ALTER table %s DROP column %s cascade" % (model._table, field.name)) + cr.execute('ALTER table "%s" DROP column "%s" cascade' % (model._table, field.name)) model._columns.pop(field.name, None) return True From 5bf4aa302a4aa01556dcafc1a02ea4e465e83c3b Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Mon, 12 Mar 2012 15:23:55 +0530 Subject: [PATCH 07/24] [ADD]: ADd condition for insert constraint if not exists. bzr revid: atp@tinyerp.com-20120312095355-q3r8bz8i7n50bf47 --- openerp/osv/orm.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 40a4f4183ff..3b728ce91dc 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -3208,8 +3208,10 @@ class BaseModel(object): cr.commit() _schema.debug(sql_action['msg_ok']) name_id = 'constraint_'+ conname + cr.execute('select conname from pg_constraint where contype=%s and conname=%s',('u', conname),) + existing_const = cr.fetchall() cr.execute('select * from ir_model_data where name=%s and module=%s', (name_id, module)) - if not cr.rowcount: + if not cr.rowcount and not existing_const: 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) ) From 4fac55615969880f4afd3aac8e81aa459c0c8b00 Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Thu, 15 Mar 2012 12:53:44 +0530 Subject: [PATCH 08/24] [FIX]: Fix dependency problem. bzr revid: atp@tinyerp.com-20120315072344-fu9h9nepujdisa2d --- openerp/addons/base/module/module.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index d6732681fb2..6adfc2dcd6d 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -392,7 +392,8 @@ class module(osv.osv): # should we call process_end istead of loading, or both ? return True - def button_uninstall(self, cr, uid, ids, context=None): + def check_dependancy(self, cr, uid, ids, context): + res = [] for module in self.browse(cr, uid, ids): cr.execute('''select m.id from @@ -403,11 +404,15 @@ class module(osv.osv): d.name=%s and m.state not in ('uninstalled','uninstallable','to remove')''', (module.name,)) res = cr.fetchall() - 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))) + return res + + def button_uninstall(self, cr, uid, ids, context=None): + res = self.check_dependancy(cr, uid, ids, context) + for i in range(0,len(res)): + res_depend = self.check_dependancy(cr, uid, [res[i][0]], context) + for j in range(0,len(res_depend)): + ids.append(res_depend[j][0]) + ids.append(res[i][0]) self.write(cr, uid, ids, {'state': 'to remove'}) return dict(ACTION_DICT, name=_('Uninstall')) From 0102e40253f7103f2d41e5d8b1ec416e2be33f76 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 21 Mar 2012 16:15:23 +0100 Subject: [PATCH 09/24] [IMP] ir.model: lint cleanup bzr revid: odo@openerp.com-20120321151523-vy01phnlz1zinldo --- openerp/addons/base/ir/ir_model.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 4d16dc8b935..1dcd78d62ce 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -1,5 +1,5 @@ +# -*- coding: utf-8 -*- - # -*- coding: utf-8 -*- ############################################################################## # # OpenERP, Open Source Management Solution @@ -74,7 +74,7 @@ class ir_model(osv.osv): def _search_osv_memory(self, cr, uid, model, name, domain, context=None): if not domain: return [] - field, operator, value = domain[0] + _, operator, value = domain[0] if operator not in ['=', '!=']: raise osv.except_osv(_('Invalid search criterions'), _('The osv_memory field can only be compared with = and != operator.')) value = bool(value) if operator == '=' else not bool(value) @@ -315,7 +315,7 @@ class ir_model_fields(osv.osv): raise except_orm(_('Error'), _("Custom fields must have a name that starts with 'x_' !")) if vals.get('relation',False) and not self.pool.get('ir.model').search(cr, user, [('model','=',vals['relation'])]): - raise except_orm(_('Error'), _("Model %s does not exist!") % vals['relation']) + raise except_orm(_('Error'), _("Model %s does not exist!") % vals['relation']) if self.pool.get(vals['model']): self.pool.get(vals['model']).__init__(self.pool, cr) @@ -434,7 +434,7 @@ class ir_model_fields(osv.osv): ctx = context.copy() ctx.update({'select': vals.get('select_level','0'),'update_custom_fields':True}) - for model_key, patch_struct in models_patch.items(): + for _, patch_struct in models_patch.items(): obj = patch_struct[0] for col_name, col_prop, val in patch_struct[1]: setattr(obj._columns[col_name], col_prop, val) @@ -828,8 +828,8 @@ class ir_model_data(osv.osv): # test if constraint exists cr.execute('select conname from pg_constraint where contype=%s and conname=%s',('f', name),) if cr.fetchall(): - cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model,name),) - _logger.info('Drop CONSTRAINT %s@%s', name, model) + cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model,name),) + _logger.info('Drop CONSTRAINT %s@%s', name, model) continue if str(name).startswith('table_'): @@ -840,7 +840,7 @@ class ir_model_data(osv.osv): continue if str(name).startswith('constraint_'): - # test if constraint exists + # test if constraint exists cr.execute('select conname from pg_constraint where contype=%s and conname=%s',('u', name),) if cr.fetchall(): cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table,name[11:]),) @@ -856,7 +856,7 @@ class ir_model_data(osv.osv): for model,res_id in wkf_todo: wf_service = netsvc.LocalService("workflow") try: - wf_service.trg_write(uid, model, res_id, cr) + wf_service.trg_write(uid, model, res_id, cr) except: _logger.info('Unable to process workflow %s@%s', res_id, model) @@ -911,7 +911,6 @@ class ir_model_data(osv.osv): if not modules: return True modules = list(modules) - data_ids = self.search(cr, uid, [('module','in',modules)]) module_in = ",".join(["%s"] * len(modules)) process_query = 'select id,name,model,res_id,module from ir_model_data where module IN (' + module_in + ')' process_query+= ' and noupdate=%s' @@ -926,6 +925,5 @@ class ir_model_data(osv.osv): _logger.info('Deleting %s@%s', res_id, model) self.pool.get(model).unlink(cr, uid, [res_id]) -ir_model_data() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 3f4a2247559d36be8125ece8d1e9682591172aac Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 22 Mar 2012 12:21:34 +0100 Subject: [PATCH 10/24] [IMP] module: lint cleanup bzr revid: odo@openerp.com-20120322112134-5ov5cphbjpxgwj87 --- openerp/addons/base/module/module.py | 46 +++++++++++----------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index 6adfc2dcd6d..5ca54d52c91 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -19,26 +19,16 @@ # along with this program. If not, see . # ############################################################################## -import base64 -import cStringIO import imp import logging -import os import re -import StringIO import urllib -import zipfile import zipimport -import openerp.modules as addons -import pooler -import release -import tools - -from tools.parse_version import parse_version -from tools.translate import _ - -from osv import fields, osv, orm +from openerp import modules, pooler, release, tools +from openerp.tools.parse_version import parse_version +from openerp.tools.translate import _ +from openerp.osv import fields, osv, orm _logger = logging.getLogger(__name__) @@ -95,7 +85,7 @@ class module(osv.osv): def get_module_info(cls, name): info = {} try: - info = addons.load_information_from_description_file(name) + info = modules.load_information_from_description_file(name) info['version'] = release.major_version + '.' + info['version'] except Exception: _logger.debug('Error when trying to fetch informations for ' @@ -165,7 +155,7 @@ class module(osv.osv): except Exception, e: _logger.warning('Unknown error while fetching data of %s', module_rec.name, exc_info=True) - for key, value in res.iteritems(): + for key, _ in res.iteritems(): for k, v in res[key].iteritems(): res[key][k] = "\n".join(sorted(v)) return res @@ -276,7 +266,7 @@ class module(osv.osv): while parts: part = parts.pop() try: - f, path, descr = imp.find_module(part, path and [path] or None) + _, path, _ = imp.find_module(part, path and [path] or None) except ImportError: raise ImportError('No module named %s' % (pydep,)) @@ -355,7 +345,7 @@ class module(osv.osv): """ self.button_install(cr, uid, ids, context=context) cr.commit() - db, pool = pooler.restart_pool(cr.dbname, update_module=True) + _, pool = pooler.restart_pool(cr.dbname, update_module=True) config = pool.get('res.config').next(cr, uid, [], context=context) or {} if config.get('type') not in ('ir.actions.reload', 'ir.actions.act_window_close'): @@ -409,10 +399,10 @@ class module(osv.osv): def button_uninstall(self, cr, uid, ids, context=None): res = self.check_dependancy(cr, uid, ids, context) for i in range(0,len(res)): - res_depend = self.check_dependancy(cr, uid, [res[i][0]], context) - for j in range(0,len(res_depend)): + res_depend = self.check_dependancy(cr, uid, [res[i][0]], context) + for j in range(0,len(res_depend)): ids.append(res_depend[j][0]) - ids.append(res[i][0]) + ids.append(res[i][0]) self.write(cr, uid, ids, {'state': 'to remove'}) return dict(ACTION_DICT, name=_('Uninstall')) @@ -486,7 +476,7 @@ class module(osv.osv): known_mods_names = dict([(m.name, m) for m in known_mods]) # iterate through detected modules and update/create them in db - for mod_name in addons.get_modules(): + for mod_name in modules.get_modules(): mod = known_mods_names.get(mod_name) terp = self.get_module_info(mod_name) values = self.get_values_from_terp(terp) @@ -505,7 +495,7 @@ class module(osv.osv): if updated_values: self.write(cr, uid, mod.id, updated_values) else: - mod_path = addons.get_module_path(mod_name) + mod_path = modules.get_module_path(mod_name) if not mod_path: continue if not terp or not terp.get('installable', True): @@ -534,7 +524,7 @@ class module(osv.osv): if not download: continue zip_content = urllib.urlopen(mod.url).read() - fname = addons.get_module_path(str(mod.name)+'.zip', downloaded=True) + fname = modules.get_module_path(str(mod.name)+'.zip', downloaded=True) try: with open(fname, 'wb') as fp: fp.write(zip_content) @@ -604,17 +594,17 @@ class module(osv.osv): for mod in self.browse(cr, uid, ids): if mod.state != 'installed': continue - modpath = addons.get_module_path(mod.name) + modpath = modules.get_module_path(mod.name) if not modpath: # unable to find the module. we skip continue for lang in filter_lang: iso_lang = tools.get_iso_codes(lang) - f = addons.get_module_resource(mod.name, 'i18n', iso_lang + '.po') + f = modules.get_module_resource(mod.name, 'i18n', iso_lang + '.po') context2 = context and context.copy() or {} if f and '_' in iso_lang: iso_lang2 = iso_lang.split('_')[0] - f2 = addons.get_module_resource(mod.name, 'i18n', iso_lang2 + '.po') + f2 = modules.get_module_resource(mod.name, 'i18n', iso_lang2 + '.po') if f2: _logger.info('module %s: loading base translation file %s for language %s', mod.name, iso_lang2, lang) tools.trans_load(cr, f2, lang, verbose=False, context=context) @@ -624,7 +614,7 @@ class module(osv.osv): # like "en". if (not f) and '_' in iso_lang: iso_lang = iso_lang.split('_')[0] - f = addons.get_module_resource(mod.name, 'i18n', iso_lang + '.po') + f = modules.get_module_resource(mod.name, 'i18n', iso_lang + '.po') if f: _logger.info('module %s: loading translation file (%s) for language %s', mod.name, iso_lang, lang) tools.trans_load(cr, f, lang, verbose=False, context=context2) From 5dc5c0814d3603c00f97d4885012fb1f650dc070 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 22 Mar 2012 17:01:23 +0100 Subject: [PATCH 11/24] [IMP] module: add a warning when uninstalling a module, as we will now delete data! bzr revid: odo@openerp.com-20120322160123-jwukwtb7l5vp8hw4 --- openerp/addons/base/module/module_view.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/module/module_view.xml b/openerp/addons/base/module/module_view.xml index c1361401414..0005aee98ff 100644 --- a/openerp/addons/base/module/module_view.xml +++ b/openerp/addons/base/module/module_view.xml @@ -153,7 +153,9 @@