← Back to team overview

clearcorp team mailing list archive

lp:~wg.clearcorp/openerp-ccorp-addons/6.1-instance-generic-merge into lp:openerp-ccorp-addons

 

Willy Andres Gomez Solorzano has proposed merging lp:~wg.clearcorp/openerp-ccorp-addons/6.1-instance-generic-merge into lp:openerp-ccorp-addons.

Requested reviews:
  Ronald Rubi (rr.clearcorp)

For more details, see:
https://code.launchpad.net/~wg.clearcorp/openerp-ccorp-addons/6.1-instance-generic-merge/+merge/146144

Fixed error of unique constraint in rel tables
-- 
https://code.launchpad.net/~wg.clearcorp/openerp-ccorp-addons/6.1-instance-generic-merge/+merge/146144
Your team CLEARCORP development team is subscribed to branch lp:openerp-ccorp-addons.
=== added file 'generic_instance_merge/foreign_query.sql'
--- generic_instance_merge/foreign_query.sql	1970-01-01 00:00:00 +0000
+++ generic_instance_merge/foreign_query.sql	2013-02-01 15:02:27 +0000
@@ -0,0 +1,12 @@
+SELECT A.relname AS tabla, C.attname AS columna, B.relname AS tabla_foranea, D.attname AS columna_foranea
+            FROM pg_catalog.pg_constraint, pg_catalog.pg_class AS A, pg_catalog.pg_class AS B, pg_catalog.pg_attribute C, pg_catalog.pg_attribute D 
+            WHERE contype = 'f'
+            AND conrelid = A.oid 
+            AND confrelid = B.oid 
+            AND conrelid = C.attrelid 
+            AND confrelid = D.attrelid 
+            AND C.attnum = pg_catalog.pg_constraint.conkey[1] 
+            AND D.attnum = pg_catalog.pg_constraint.confkey[1] 
+--            AND B.relname =''
+--          AND D.attname ='id'
+            ORDER BY tabla, columna, tabla_foranea, columna_foranea; 

=== modified file 'generic_instance_merge/generic_instance_merge.py'
--- generic_instance_merge/generic_instance_merge.py	2013-01-21 20:54:37 +0000
+++ generic_instance_merge/generic_instance_merge.py	2013-02-01 15:02:27 +0000
@@ -26,12 +26,48 @@
 import tools
 from tools.translate import _
 
+
 class generic_instance_merge(orm.Model):
     _name =  "generic.instance.merge"
     _description = "Generic merging Library"
     
-   
+    def get_values(self, msg, ref_field):
+        '''
+        Parses the error message "msg" to get the columns and values that produce integrity error.
+        Arguments:
+            "msg" - String, with the error message
+            "ref_field" - String, with the name of the referencing column  
+        Returns:
+            key_values - List of dictionaries
+        ''' 
+        tmp = msg.split('=')
+        columns = tmp[0]
+        values = tmp[1]
+        
+        tmp = columns.split('(')
+        columns = tmp[1]
+        comma_index=columns.find(',')
+        paren_index=columns.find(')')
+        field_1 =  columns[0:comma_index]
+        field_2 =  columns[comma_index + 2: paren_index]
+        
+        comma_index=values.find(',')
+        paren_index=values.find(')')
+        value_1 =  values[1:comma_index]
+        value_2 =  values[comma_index +2: paren_index]
+        
+        if ref_field == field_1: #if the referencing field is the field_1, field/value_1 goes first
+            key_values = [{'column' : field_1, 'value' : value_1 },{'column' : field_2, 'value' : value_2 }]
+        else:#  field/value_1 goes second
+            key_values = [{'column' : field_2, 'value' : value_2 },{'column' : field_1, 'value' : value_1 }]
+        return key_values
     
+    def is_integrity_error(self, pgcode):
+        if pgcode == '23505':
+            return True
+        else:
+            return False
+
     def merge(self, cr, uid,obj_class, id, ids, delete_merged=False, context=None):
         '''
                 redirects all references from an "obj_class" instance with id in "ids" to the instance of "id"  
@@ -56,19 +92,34 @@
             'AND B.relname ='+"\'"+ obj_class +"\' " \
             'AND D.attname ='+"\'id\' " \
             'ORDER BY tabla, columna, tabla_foranea, columna_foranea;'
-        cr.execute(dependencies_query)
+        cr.execute(dependencies_query) #gets foreign references to id 
         for line in cr.fetchall():
             referencing_table = line[0]
             referencing_field = line[1] 
-            for merging_id in ids:
-                update_query="UPDATE "+ referencing_table + \
-                " SET "+ referencing_field +" = "+ str(id) + \
-                " WHERE "+ referencing_field +" = "+ str(merging_id) 
-                cr.execute(update_query)
+            for merging_id in ids: #for every reference, replaces the field id with value "id" 
+                clean_exit = False  #loop in case that an exception raises, until the respective ids are updated or deleted
+                while clean_exit == False:
+                    try:
+                        update_query= "UPDATE "+ referencing_table + \
+                            " SET "+ referencing_field +" = "+ str(id) + \
+                            " WHERE "+ referencing_field +" = "+ str(merging_id)
+                        cr.execute(update_query)
+                        clean_exit = True
+                        cr.commit()
+                    except Exception , e:
+                        cr.rollback()
+                        err=e[0]
+                        if self.is_integrity_error(e.pgcode): 
+                            values = self.get_values(err, referencing_field) #in case of integrity error gets columns/values producing the conflict   
+                            delete_query = "DELETE FROM "+ referencing_table + \
+                            " WHERE "+ values[0]['column'] +" = " + str(merging_id) + \
+                            " AND "+ values[1]['column'] +" = " + values[1]['value']
+                            cr.execute(delete_query)
+                            print "***************************"
         if delete_merged:
             for deleting_id in ids: 
                 if deleting_id != id:
-                    delete_query = "DELETE FROM "+ obj_class + \
-                        " WHERE id = "+ str(deleting_id)
+                    delete_query = "DELETE FROM " + obj_class + \
+                        " WHERE id = " + str(deleting_id)
                     cr.execute(delete_query)
         return True


Follow ups