|
|
@@ -0,0 +1,249 @@
|
|
|
+# -*- coding: utf-8 -*-
|
|
|
+"""
|
|
|
+Migration script to integrate helpdesk.template with helpdesk.workflow.template
|
|
|
+
|
|
|
+This script migrates all helpdesk.template records to helpdesk.workflow.template,
|
|
|
+moving field_ids from template to workflow_template.
|
|
|
+"""
|
|
|
+import logging
|
|
|
+from odoo import api, SUPERUSER_ID
|
|
|
+
|
|
|
+_logger = logging.getLogger(__name__)
|
|
|
+
|
|
|
+
|
|
|
+def migrate(cr, version):
|
|
|
+ """Migrate helpdesk.template to helpdesk.workflow.template"""
|
|
|
+ try:
|
|
|
+ env = api.Environment(cr, SUPERUSER_ID, {})
|
|
|
+
|
|
|
+ _logger.info("=" * 80)
|
|
|
+ _logger.info("Starting migration: helpdesk.template -> helpdesk.workflow.template")
|
|
|
+ _logger.info("=" * 80)
|
|
|
+
|
|
|
+ # 0. Verify pre-migration completed (workflow_template_id column exists)
|
|
|
+ cr.execute("""
|
|
|
+ SELECT column_name
|
|
|
+ FROM information_schema.columns
|
|
|
+ WHERE table_name = 'helpdesk_template_field'
|
|
|
+ AND column_name = 'workflow_template_id'
|
|
|
+ """)
|
|
|
+ if not cr.fetchone():
|
|
|
+ _logger.error("❌ Pre-migration not completed! workflow_template_id column does not exist.")
|
|
|
+ _logger.error("Module update will fail. Please check pre-migration logs.")
|
|
|
+ raise Exception("Pre-migration required: workflow_template_id column missing")
|
|
|
+
|
|
|
+ _logger.info("✅ Pre-migration verified: workflow_template_id column exists")
|
|
|
+
|
|
|
+ # 1. Get all helpdesk.template records
|
|
|
+ templates = env['helpdesk.template'].search([])
|
|
|
+ _logger.info(f"Found {len(templates)} template(s) to migrate")
|
|
|
+
|
|
|
+ if not templates:
|
|
|
+ _logger.info("No templates to migrate. Migration complete.")
|
|
|
+ cr.commit()
|
|
|
+ return
|
|
|
+
|
|
|
+ migrated_count = 0
|
|
|
+ skipped_count = 0
|
|
|
+ error_count = 0
|
|
|
+
|
|
|
+ # 2. For each template, migrate to workflow template
|
|
|
+ for template in templates:
|
|
|
+ try:
|
|
|
+ _logger.info(f"\nProcessing template: {template.name} (ID: {template.id})")
|
|
|
+
|
|
|
+ # First, check which teams use this template
|
|
|
+ teams_using_template = env['helpdesk.team'].search([
|
|
|
+ ('template_id', '=', template.id)
|
|
|
+ ])
|
|
|
+
|
|
|
+ _logger.info(f" Found {len(teams_using_template)} team(s) using this template")
|
|
|
+
|
|
|
+ # Group teams by whether they have workflow_template_id or not
|
|
|
+ teams_with_workflow = teams_using_template.filtered('workflow_template_id')
|
|
|
+ teams_without_workflow = teams_using_template.filtered(lambda t: not t.workflow_template_id)
|
|
|
+
|
|
|
+ workflow_template = None
|
|
|
+
|
|
|
+ # Strategy 1: If teams have workflow_template_id, migrate fields to their existing workflow
|
|
|
+ if teams_with_workflow:
|
|
|
+ # Check if all teams use the same workflow_template_id
|
|
|
+ workflow_ids = teams_with_workflow.mapped('workflow_template_id.id')
|
|
|
+ unique_workflows = set(workflow_ids)
|
|
|
+
|
|
|
+ if len(unique_workflows) == 1:
|
|
|
+ # All teams use the same workflow template - migrate fields there
|
|
|
+ workflow_template = teams_with_workflow[0].workflow_template_id
|
|
|
+ _logger.info(f" All teams use workflow template '{workflow_template.name}' (ID: {workflow_template.id})")
|
|
|
+ _logger.info(f" Migrating fields from template to existing workflow template...")
|
|
|
+ else:
|
|
|
+ # Teams use different workflow templates - use the most common one
|
|
|
+ from collections import Counter
|
|
|
+ workflow_counter = Counter(workflow_ids)
|
|
|
+ most_common_workflow_id = workflow_counter.most_common(1)[0][0]
|
|
|
+ workflow_template = env['helpdesk.workflow.template'].browse(most_common_workflow_id)
|
|
|
+ _logger.info(f" Teams use different workflow templates. Using most common: '{workflow_template.name}' (ID: {workflow_template.id})")
|
|
|
+ _logger.info(f" Migrating fields from template to this workflow template...")
|
|
|
+
|
|
|
+ # Strategy 2: If no teams have workflow_template_id, create/find workflow template
|
|
|
+ if not workflow_template:
|
|
|
+ # Check if a workflow template with the same name already exists
|
|
|
+ workflow_template = env['helpdesk.workflow.template'].search([
|
|
|
+ ('name', '=', template.name)
|
|
|
+ ], limit=1)
|
|
|
+
|
|
|
+ if workflow_template:
|
|
|
+ _logger.info(f" Workflow template '{workflow_template.name}' already exists (ID: {workflow_template.id})")
|
|
|
+ _logger.info(f" Migrating fields from template into existing workflow template...")
|
|
|
+ else:
|
|
|
+ # Create new workflow template
|
|
|
+ workflow_template = env['helpdesk.workflow.template'].create({
|
|
|
+ 'name': template.name,
|
|
|
+ 'description': template.description or False,
|
|
|
+ 'active': template.active,
|
|
|
+ })
|
|
|
+ _logger.info(f" Created new workflow template: {workflow_template.name} (ID: {workflow_template.id})")
|
|
|
+
|
|
|
+ # 3. Migrate field_ids from template to workflow_template
|
|
|
+ field_count = 0
|
|
|
+ for field in template.field_ids:
|
|
|
+ try:
|
|
|
+ # Check if field already exists in workflow template
|
|
|
+ existing_field = env['helpdesk.template.field'].search([
|
|
|
+ ('workflow_template_id', '=', workflow_template.id),
|
|
|
+ ('field_id', '=', field.field_id.id)
|
|
|
+ ], limit=1)
|
|
|
+
|
|
|
+ if existing_field:
|
|
|
+ _logger.warning(f" Field '{field.field_id.name}' already exists in workflow template. Skipping.")
|
|
|
+ continue
|
|
|
+
|
|
|
+ # Update field to point to workflow_template_id instead of template_id
|
|
|
+ field.write({
|
|
|
+ 'template_id': False, # Clear legacy reference
|
|
|
+ 'workflow_template_id': workflow_template.id, # Set new reference
|
|
|
+ })
|
|
|
+ field_count += 1
|
|
|
+ _logger.info(f" Migrated field: {field.field_id.name}")
|
|
|
+ except Exception as e:
|
|
|
+ _logger.error(f" Error migrating field {field.id}: {e}", exc_info=True)
|
|
|
+ error_count += 1
|
|
|
+ continue
|
|
|
+
|
|
|
+ _logger.info(f" Migrated {field_count} field(s) to workflow template")
|
|
|
+
|
|
|
+ # 4. Update teams that use this template
|
|
|
+ team_count = 0
|
|
|
+ for team in teams_using_template:
|
|
|
+ try:
|
|
|
+ # If team doesn't have workflow_template_id, assign it
|
|
|
+ if not team.workflow_template_id:
|
|
|
+ team.write({
|
|
|
+ 'workflow_template_id': workflow_template.id,
|
|
|
+ 'template_id': False, # Clear legacy reference
|
|
|
+ })
|
|
|
+ team_count += 1
|
|
|
+ _logger.info(f" Updated team: {team.name} (ID: {team.id}) - assigned workflow template")
|
|
|
+ else:
|
|
|
+ # Team already has workflow_template_id
|
|
|
+ # If we migrated fields to a different workflow, update it
|
|
|
+ if team.workflow_template_id.id != workflow_template.id:
|
|
|
+ _logger.info(f" Team {team.name} had workflow '{team.workflow_template_id.name}', updating to '{workflow_template.name}'")
|
|
|
+ team.write({
|
|
|
+ 'workflow_template_id': workflow_template.id,
|
|
|
+ 'template_id': False, # Clear legacy reference
|
|
|
+ })
|
|
|
+ team_count += 1
|
|
|
+ else:
|
|
|
+ # Same workflow template - just clear template_id
|
|
|
+ team.write({
|
|
|
+ 'template_id': False, # Clear legacy reference
|
|
|
+ })
|
|
|
+ _logger.info(f" Team {team.name} already uses workflow '{workflow_template.name}'. Cleared template_id only.")
|
|
|
+ except Exception as e:
|
|
|
+ _logger.error(f" Error updating team {team.id}: {e}", exc_info=True)
|
|
|
+ error_count += 1
|
|
|
+ continue
|
|
|
+
|
|
|
+ _logger.info(f" Updated {team_count} team(s)")
|
|
|
+
|
|
|
+ # 5. Regenerate forms for affected teams (skip in production if too many)
|
|
|
+ teams_affected = env['helpdesk.team'].search([
|
|
|
+ ('workflow_template_id', '=', workflow_template.id),
|
|
|
+ ('use_website_helpdesk_form', '=', True)
|
|
|
+ ])
|
|
|
+
|
|
|
+ # Limit regeneration to avoid timeout in production
|
|
|
+ max_teams_to_regenerate = 50
|
|
|
+ if len(teams_affected) > max_teams_to_regenerate:
|
|
|
+ _logger.warning(f" Too many teams ({len(teams_affected)}) to regenerate. Skipping automatic regeneration.")
|
|
|
+ _logger.warning(f" Please regenerate forms manually or via cron.")
|
|
|
+ else:
|
|
|
+ for team in teams_affected:
|
|
|
+ if team.website_form_view_id:
|
|
|
+ try:
|
|
|
+ team._regenerate_form_from_template()
|
|
|
+ _logger.info(f" Regenerated form for team: {team.name}")
|
|
|
+ except Exception as e:
|
|
|
+ _logger.warning(f" Could not regenerate form for team {team.id}: {e}")
|
|
|
+ # Don't fail migration if form regeneration fails
|
|
|
+ continue
|
|
|
+
|
|
|
+ migrated_count += 1
|
|
|
+ _logger.info(f"✅ Successfully migrated template: {template.name}")
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ _logger.error(f"❌ Error migrating template {template.id} ({template.name}): {e}", exc_info=True)
|
|
|
+ error_count += 1
|
|
|
+ skipped_count += 1
|
|
|
+ continue
|
|
|
+
|
|
|
+ # 6. Summary
|
|
|
+ _logger.info("\n" + "=" * 80)
|
|
|
+ _logger.info("Migration Summary:")
|
|
|
+ _logger.info(f" Templates processed: {len(templates)}")
|
|
|
+ _logger.info(f" Successfully migrated: {migrated_count}")
|
|
|
+ _logger.info(f" Skipped/Errors: {skipped_count}")
|
|
|
+ _logger.info(f" Total errors: {error_count}")
|
|
|
+ _logger.info("=" * 80)
|
|
|
+
|
|
|
+ # 7. Verify migration
|
|
|
+ remaining_templates = env['helpdesk.template'].search([])
|
|
|
+ if remaining_templates:
|
|
|
+ _logger.warning(f"⚠️ {len(remaining_templates)} template(s) still exist. They may have errors or were skipped.")
|
|
|
+ else:
|
|
|
+ _logger.info("✅ All templates migrated successfully")
|
|
|
+
|
|
|
+ # Check for orphaned fields (fields with template_id but no workflow_template_id)
|
|
|
+ orphaned_fields = env['helpdesk.template.field'].search([
|
|
|
+ ('template_id', '!=', False),
|
|
|
+ ('workflow_template_id', '=', False)
|
|
|
+ ])
|
|
|
+ if orphaned_fields:
|
|
|
+ _logger.warning(f"⚠️ Found {len(orphaned_fields)} orphaned field(s) (have template_id but no workflow_template_id)")
|
|
|
+ _logger.warning(f" These fields will need manual migration or will be cleaned up later.")
|
|
|
+
|
|
|
+ # Commit only if we have successful migrations or no templates to migrate
|
|
|
+ if migrated_count > 0 or len(templates) == 0:
|
|
|
+ cr.commit()
|
|
|
+ _logger.info("✅ Migration completed successfully")
|
|
|
+ else:
|
|
|
+ # If all templates failed, rollback but don't block module update
|
|
|
+ # (data might be corrupted, but module structure is OK)
|
|
|
+ _logger.error("⚠️ All templates failed to migrate. Rolling back data changes.")
|
|
|
+ try:
|
|
|
+ cr.rollback()
|
|
|
+ except Exception:
|
|
|
+ pass
|
|
|
+ _logger.error("Module update will continue, but data migration needs manual intervention.")
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ _logger.error(f"❌ Critical error in migration: {e}", exc_info=True)
|
|
|
+ try:
|
|
|
+ cr.rollback()
|
|
|
+ except Exception:
|
|
|
+ pass
|
|
|
+ # Don't raise - allow module update to complete even if migration fails
|
|
|
+ # The module structure is OK, only data migration failed
|
|
|
+ _logger.error("Migration failed but module update will continue. Please review logs and fix manually if needed.")
|
|
|
+
|