| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- # -*- 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.")
|