Atul Patel(OpenERP) has proposed merging 
lp:~openerp-dev/openobject-server/trunk-uninstall_modules-atp into 
lp:openobject-server.

Requested reviews:
  Harry (OpenERP) (hmo-tinyerp)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-uninstall_modules-atp/+merge/96807

Hello,
I have uninstall module. For that

   1) Remove foreign key references.
   2) Remove sql constraint .
   3) Remove workflow activity and transition based on deleted cascade.
   4) Drop ir model fields columns and drop table.

Thanks
Atul
-- 
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-uninstall_modules-atp/+merge/96807
Your team OpenERP R&D Team is subscribed to branch 
lp:~openerp-dev/openobject-server/trunk-uninstall_modules-atp.
=== modified file 'openerp/addons/base/ir/ir_actions.py'
--- openerp/addons/base/ir/ir_actions.py	2012-01-31 21:17:44 +0000
+++ openerp/addons/base/ir/ir_actions.py	2012-03-09 18:33:19 +0000
@@ -510,7 +510,7 @@
         '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)"),

=== modified file 'openerp/addons/base/ir/ir_model.py'
--- openerp/addons/base/ir/ir_model.py	2012-02-09 08:38:28 +0000
+++ openerp/addons/base/ir/ir_model.py	2012-03-09 18:33:19 +0000
@@ -1,4 +1,5 @@
-# -*- coding: utf-8 -*-
+
+ # -*- coding: utf-8 -*-
 ##############################################################################
 #
 #    OpenERP, Open Source Management Solution
@@ -134,11 +135,24 @@
                              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)
+            # 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,))
+#        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 +277,23 @@
     _sql_constraints = [
         ('size_gt_zero', 'CHECK (size>0)',_size_gt_zero_msg ),
     ]
+    
+    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,))
+        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):
-        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:
@@ -620,10 +640,10 @@
     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 = {}
+            
         self.loads = self.pool.model_data_reference_ids
 
     def _auto_init(self, cr, context=None):
@@ -667,6 +687,7 @@
         except:
             id = False
         return id
+    
 
     def unlink(self, cr, uid, ids, context=None):
         """ Regular unlink method, but make sure to clear the caches. """
@@ -678,17 +699,14 @@
         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('.')
         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 +809,121 @@
         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 = []
+        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)
+            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
+            
+            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))
+
+        for model,res_id in wkf_todo:
+            wf_service = netsvc.LocalService("workflow")
+            try:
+               wf_service.trg_write(uid, model, res_id, cr)
+            except:
+                _logger.info('Unable to process workflow %s@%s', 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.
-
         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()
         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])
+                    
 ir_model_data()
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== modified file 'openerp/addons/base/ir/ir_rule.py'
--- openerp/addons/base/ir/ir_rule.py	2012-02-13 11:01:44 +0000
+++ openerp/addons/base/ir/ir_rule.py	2012-03-09 18:33:19 +0000
@@ -75,7 +75,7 @@
 
     _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'),

=== modified file 'openerp/addons/base/ir/workflow/workflow.py'
--- openerp/addons/base/ir/workflow/workflow.py	2011-11-07 15:19:49 +0000
+++ openerp/addons/base/ir/workflow/workflow.py	2012-03-09 18:33:19 +0000
@@ -194,7 +194,7 @@
     _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),

=== modified file 'openerp/addons/base/module/module.py'
--- openerp/addons/base/module/module.py	2012-02-14 15:18:46 +0000
+++ openerp/addons/base/module/module.py	2012-03-09 18:33:19 +0000
@@ -343,7 +343,6 @@
         # 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):
@@ -375,10 +374,27 @@
     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):
+
+        # 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):
         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 +403,11 @@
                     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'))
 

=== modified file 'openerp/addons/base/module/wizard/base_module_upgrade.py'
--- openerp/addons/base/module/wizard/base_module_upgrade.py	2011-11-22 08:58:48 +0000
+++ openerp/addons/base/module/wizard/base_module_upgrade.py	2012-03-09 18:33:19 +0000
@@ -83,7 +83,9 @@
 
     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,12 @@
             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

=== modified file 'openerp/addons/base/res/res_users.py'
--- openerp/addons/base/res/res_users.py	2012-02-13 18:32:07 +0000
+++ openerp/addons/base/res/res_users.py	2012-03-09 18:33:19 +0000
@@ -53,7 +53,7 @@
 
     _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)]),
@@ -107,21 +107,6 @@
                 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')

=== modified file 'openerp/modules/loading.py'
--- openerp/modules/loading.py	2012-03-02 11:28:34 +0000
+++ openerp/modules/loading.py	2012-03-09 18:33:19 +0000
@@ -383,45 +383,47 @@
             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',))
-            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
+            #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.
             # 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',))
-            cr.commit()
+            #cr.execute("update ir_module_module set state=%s where state=%s", ('uninstalled', 'to remove',))
+            #cr.commit()
 
         if report.failures:
             _logger.error('At least one test failed when loading the modules.')

=== modified file 'openerp/osv/orm.py'
--- openerp/osv/orm.py	2012-02-15 10:17:14 +0000
+++ openerp/osv/orm.py	2012-03-09 18:33:19 +0000
@@ -904,6 +904,7 @@
                                     # 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 @@
         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:
@@ -3018,7 +3018,7 @@
 
         cr.commit()     # start a new transaction
 
-        self._add_sql_constraints(cr)
+        self._add_sql_constraints(cr, context["module"])
 
         if create:
             self._execute_sql(cr)
@@ -3029,11 +3029,16 @@
 
         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 @@
 
     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 @@
                 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 @@
             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():
@@ -3145,7 +3157,7 @@
             _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
@@ -3157,7 +3169,6 @@
 
             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,
@@ -3196,6 +3207,12 @@
                     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 +3727,7 @@
         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')

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to