- Add v3.4-v3.8 and v4.2 to migration registry - Remove v3.9 (master-only supplier_catalog_prices table) - Ensures new tenants like La Casita get all schema updates
126 lines
3.8 KiB
Python
Executable File
126 lines
3.8 KiB
Python
Executable File
#!/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',
|
|
'v3.4': 'v3.4_meli_integration.sql',
|
|
'v3.5': 'v3.5_meli_questions.sql',
|
|
'v3.6': 'v3.6_dropshipping.sql',
|
|
'v3.7': 'v3.7_sku_aliases.sql',
|
|
'v3.8': 'v3.8_supplier_catalog.sql',
|
|
'v4.0': 'v4.0_multi_branch.sql',
|
|
'v4.1': 'v4.1_global_invoice.sql',
|
|
'v4.2': 'v4.2_meli_sync_queue.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()
|