"""remove subscription_tier from tenants Revision ID: 20251028_remove_sub_tier Revises: 20251025_supplier_approval Create Date: 2025-10-28 12:00:00.000000 This migration removes the denormalized subscription_tier column from the tenants table. The subscription tier is now sourced exclusively from the subscriptions table (single source of truth). """ from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision = '20251028_remove_sub_tier' down_revision = '20251025_supplier_approval' branch_labels = None depends_on = None def upgrade(): """ Remove subscription_tier column from tenants table """ # Pre-flight check: Ensure all tenants have active subscriptions # This is important to avoid breaking the application connection = op.get_bind() # Check for tenants without subscriptions result = connection.execute(sa.text(""" SELECT COUNT(*) as count FROM tenants t LEFT JOIN subscriptions s ON t.id = s.tenant_id AND s.status = 'active' WHERE s.id IS NULL """)) orphaned_count = result.fetchone()[0] if orphaned_count > 0: # Create default subscriptions for orphaned tenants connection.execute(sa.text(""" INSERT INTO subscriptions ( id, tenant_id, plan, status, monthly_price, billing_cycle, max_users, max_locations, max_products, features, created_at, updated_at ) SELECT gen_random_uuid(), t.id, 'starter', 'active', 49.0, 'monthly', 5, 1, 50, '{"inventory_management": true, "demand_prediction": true}'::jsonb, NOW(), NOW() FROM tenants t LEFT JOIN subscriptions s ON t.id = s.tenant_id AND s.status = 'active' WHERE s.id IS NULL """)) print(f"Created default subscriptions for {orphaned_count} tenants without subscriptions") # Drop the subscription_tier column op.drop_column('tenants', 'subscription_tier') print("Successfully removed subscription_tier column from tenants table") def downgrade(): """ Re-add subscription_tier column and populate from subscriptions table Note: This is for rollback purposes only. Going forward, always use subscriptions table. """ # Add the column back op.add_column('tenants', sa.Column('subscription_tier', sa.String(length=50), nullable=True) ) # Populate from subscriptions table connection = op.get_bind() connection.execute(sa.text(""" UPDATE tenants t SET subscription_tier = s.plan FROM subscriptions s WHERE t.id = s.tenant_id AND s.status = 'active' """)) # Set default for any tenants without active subscriptions connection.execute(sa.text(""" UPDATE tenants SET subscription_tier = 'starter' WHERE subscription_tier IS NULL """)) # Make it non-nullable after population op.alter_column('tenants', 'subscription_tier', nullable=False) print("Restored subscription_tier column (downgrade)")