#!/usr/bin/env python3 # /home/Autopartes/pos/migrations/runner.py """Apply schema migrations to all tenant databases.""" import os import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from tenant_db import get_master_conn, get_tenant_conn_by_dbname MIGRATIONS_DIR = os.path.dirname(os.path.abspath(__file__)) # Migration registry: version -> filename MIGRATIONS = { 'v1.0': 'v1.0_initial.sql', 'v1.1': 'v1.1_pos_tables.sql', 'v1.3': 'v1.3_fleet.sql', 'v1.4': 'v1.4_whatsapp.sql', 'v1.5': 'v1.5_returns.sql', 'v1.7': 'v1.7_plates.sql', 'v1.8': 'v1.8_performance_indexes.sql', 'v1.9': 'v1.9_redis_cache.sql', 'v2.0': 'v2.0_multi_currency.sql', 'v2.1': 'v2.1_suppliers.sql', 'v2.2': 'v2.2_alerts_warranty.sql', 'v2.3': 'v2.3_metabase.sql', 'v2.4': 'v2.4_crm_enhanced.sql', 'v2.5': 'v2.5_service_orders.sql', 'v2.6': 'v2.6_bnpl_erp.sql', 'v2.7': 'v2.7_notifications.sql', 'v2.8': 'v2.8_savings.sql', 'v2.9': 'v2.9_logistics.sql', 'v3.0': 'v3.0_public_api.sql', 'v3.1': 'v3.1_inventory_vehicle_compat.sql', 'v3.2': 'v3.2_db_performance.sql', } def get_all_tenants(): """Get all tenants with their current schema version.""" conn = get_master_conn() cur = conn.cursor() cur.execute(""" SELECT t.id, t.db_name, t.name, COALESCE(v.version, 'v0.0') as version FROM tenants t LEFT JOIN tenant_schema_version v ON t.id = v.tenant_id WHERE t.is_active = true """) tenants = cur.fetchall() cur.close() conn.close() return tenants def apply_migration(db_name, version): """Apply a single migration to a tenant DB.""" filename = MIGRATIONS[version] filepath = os.path.join(MIGRATIONS_DIR, filename) if not os.path.exists(filepath): print(f" ERROR: Migration file not found: {filepath}") return False conn = get_tenant_conn_by_dbname(db_name) cur = conn.cursor() try: with open(filepath) as f: cur.execute(f.read()) conn.commit() return True except Exception as e: conn.rollback() print(f" ERROR: {e}") return False finally: cur.close() conn.close() def run_migrations(): """Apply pending migrations to all tenants.""" tenants = get_all_tenants() sorted_versions = sorted(MIGRATIONS.keys()) print(f"Found {len(tenants)} active tenants") print(f"Available migrations: {sorted_versions}") for tenant_id, db_name, name, current_version in tenants: print(f"\n[{name}] (db={db_name}, current={current_version})") for version in sorted_versions: if version <= current_version: continue print(f" Applying {version}...", end=' ') if apply_migration(db_name, version): # Update version in master master_conn = get_master_conn() master_cur = master_conn.cursor() master_cur.execute(""" INSERT INTO tenant_schema_version (tenant_id, version) VALUES (%s, %s) ON CONFLICT (tenant_id) DO UPDATE SET version = %s, updated_at = NOW() """, (tenant_id, version, version)) master_conn.commit() master_cur.close() master_conn.close() print("OK") else: print("FAILED — stopping migrations for this tenant") break print("\nDone.") if __name__ == '__main__': run_migrations()