Просмотр исходного кода

Fix: Reemplazar constraints UNIQUE con índices parciales únicos

- Eliminar constraints UNIQUE del modelo (no funcionan bien con NULLs)
- Agregar índices parciales únicos en pre-migration para manejar NULLs correctamente
- Los índices parciales solo aplican unicidad cuando template_id o workflow_template_id IS NOT NULL
- Esto resuelve el error de carga del módulo en producción
odoo 2 месяцев назад
Родитель
Сommit
3b802f2cc0

+ 64 - 1
helpdesk_extras/migrations/18.0.1.0.12/pre-migration.py

@@ -99,7 +99,70 @@ def migrate(cr, version):
         else:
             _logger.info("Index already exists")
         
-        # 5. Add CHECK constraint to ensure only one of template_id or workflow_template_id is set
+        # 5. Drop old UNIQUE constraints if they exist (they don't work well with NULLs)
+        cr.execute("""
+            SELECT constraint_name 
+            FROM information_schema.table_constraints 
+            WHERE table_name = 'helpdesk_template_field' 
+            AND constraint_name IN ('helpdesk_template_field_unique_template_field', 
+                                     'helpdesk_template_field_unique_workflow_template_field')
+        """)
+        old_constraints = cr.fetchall()
+        
+        for constraint in old_constraints:
+            constraint_name = constraint[0]
+            _logger.info(f"Dropping old constraint: {constraint_name}...")
+            try:
+                cr.execute(f"""
+                    ALTER TABLE helpdesk_template_field 
+                    DROP CONSTRAINT IF EXISTS {constraint_name}
+                """)
+                _logger.info(f"✅ Dropped constraint: {constraint_name}")
+            except Exception as e:
+                _logger.warning(f"Could not drop constraint {constraint_name}: {e}")
+        
+        # 6. Add partial unique indexes (work correctly with NULLs)
+        # Index for template_id + field_id (only when template_id IS NOT NULL)
+        cr.execute("""
+            SELECT indexname 
+            FROM pg_indexes 
+            WHERE tablename = 'helpdesk_template_field' 
+            AND indexname = 'helpdesk_template_field_unique_template_field_idx'
+        """)
+        template_idx_exists = cr.fetchone()
+        
+        if not template_idx_exists:
+            _logger.info("Adding partial unique index for template_id + field_id...")
+            cr.execute("""
+                CREATE UNIQUE INDEX helpdesk_template_field_unique_template_field_idx 
+                ON helpdesk_template_field(template_id, field_id)
+                WHERE template_id IS NOT NULL
+            """)
+            _logger.info("✅ Partial unique index for template_id added")
+        else:
+            _logger.info("Partial unique index for template_id already exists")
+        
+        # Index for workflow_template_id + field_id (only when workflow_template_id IS NOT NULL)
+        cr.execute("""
+            SELECT indexname 
+            FROM pg_indexes 
+            WHERE tablename = 'helpdesk_template_field' 
+            AND indexname = 'helpdesk_template_field_unique_workflow_template_field_idx'
+        """)
+        workflow_idx_exists = cr.fetchone()
+        
+        if not workflow_idx_exists:
+            _logger.info("Adding partial unique index for workflow_template_id + field_id...")
+            cr.execute("""
+                CREATE UNIQUE INDEX helpdesk_template_field_unique_workflow_template_field_idx 
+                ON helpdesk_template_field(workflow_template_id, field_id)
+                WHERE workflow_template_id IS NOT NULL
+            """)
+            _logger.info("✅ Partial unique index for workflow_template_id added")
+        else:
+            _logger.info("Partial unique index for workflow_template_id already exists")
+        
+        # 7. Add CHECK constraint to ensure only one of template_id or workflow_template_id is set
         cr.execute("""
             SELECT constraint_name 
             FROM information_schema.table_constraints 

+ 3 - 4
helpdesk_extras/models/helpdesk_template.py

@@ -513,10 +513,9 @@ class HelpdeskTemplateField(models.Model):
             self.visibility_between = False
 
     _sql_constraints = [
-        ('unique_template_field', 'unique(template_id, field_id)',
-         'A field can only be added once to a template'),
-        ('unique_workflow_template_field', 'unique(workflow_template_id, field_id)',
-         'A field can only be added once to a workflow template'),
+        # Note: UNIQUE constraints with NULLs need special handling
+        # PostgreSQL allows multiple NULLs in UNIQUE constraints, so we use partial indexes via pre-migration
+        # The CHECK constraint ensures only one of template_id or workflow_template_id is set
         # Note: CHECK constraint added via pre-migration script to avoid issues during module update
         # The constraint is: (template_id IS NOT NULL AND workflow_template_id IS NULL) OR (template_id IS NULL AND workflow_template_id IS NOT NULL)
     ]