# -*- coding: utf-8 -*- import logging from odoo import api, SUPERUSER_ID _logger = logging.getLogger(__name__) def post_init_hook(env): """ Post-installation hook to migrate existing ratings from 0-3 scale to 0-5 scale. Migration mapping: - 0 → 0 (no rating) - 1 → 3 (poor becomes 3 stars) - 2 → 4 (okay becomes 4 stars) - 3 → 5 (good becomes 5 stars) Args: env: Odoo environment """ _logger.info("Starting rating migration from 0-3 scale to 0-5 scale...") cr = env.cr # Check if we're running in test mode by checking if commit is forbidden test_mode = False try: # Try to check if we're in test mode by looking at the cursor test_mode = hasattr(cr, '__class__') and 'TestCursor' in cr.__class__.__name__ except: test_mode = False try: # Define the migration mapping migration_mapping = { 0: 0, # No rating stays 0 1: 3, # Poor (1) becomes 3 stars 2: 4, # Okay (2) becomes 4 stars 3: 5, # Good (3) becomes 5 stars } # Get all ratings that need migration (values 0-3) # We need to use SQL to avoid triggering constraints during migration cr.execute(""" SELECT id, rating FROM rating_rating WHERE rating IN (0, 1, 2, 3) """) ratings_to_migrate = cr.fetchall() total_count = len(ratings_to_migrate) if total_count == 0: _logger.info("No ratings found to migrate. Migration complete.") return _logger.info(f"Found {total_count} ratings to migrate.") # Migrate ratings in batches for better performance batch_size = 1000 migrated_count = 0 error_count = 0 for i in range(0, total_count, batch_size): batch = ratings_to_migrate[i:i + batch_size] try: # Use SQL UPDATE for better performance and to avoid constraint issues for rating_id, old_value in batch: # Only migrate if the value is in the old scale (0-3) if old_value in migration_mapping: new_value = migration_mapping[old_value] # Update using SQL to bypass ORM constraints temporarily cr.execute(""" UPDATE rating_rating SET rating = %s WHERE id = %s AND rating = %s """, (new_value, rating_id, old_value)) migrated_count += 1 # Only commit if not in test mode if not test_mode: cr.commit() _logger.info(f"Migrated batch: {migrated_count}/{total_count} ratings") except Exception as batch_error: _logger.error(f"Error migrating batch: {batch_error}") error_count += len(batch) # Only rollback if not in test mode if not test_mode: cr.rollback() continue # Final commit (only if not in test mode) if not test_mode: cr.commit() # Log final results _logger.info(f"Rating migration complete!") _logger.info(f"Successfully migrated: {migrated_count} ratings") if error_count > 0: _logger.warning(f"Failed to migrate: {error_count} ratings") # Verify migration results cr.execute(""" SELECT COUNT(*) FROM rating_rating WHERE rating > 0 AND rating < 1 """) invalid_count = cr.fetchone()[0] if invalid_count > 0: _logger.warning(f"Found {invalid_count} ratings with invalid values after migration") _logger.info("Rating migration process finished.") except Exception as e: _logger.error(f"Critical error during rating migration: {e}") # Only rollback if not in test mode if not test_mode: cr.rollback() _logger.error("Migration rolled back due to critical error.") raise