FASE 4: - Redis cache de stock con fallback graceful - Multi-moneda (MXN/USD) con contabilidad en MXN - Proveedores y ordenes de compra completo - Meilisearch 1.5M+ partes indexadas - Metabase KPIs con dashboard auto-generado FASE 5: - CRM mejorado: activities, tags, loyalty program, analytics - Imagenes de partes: upload, resize, thumbnails WebP - Ordenes de servicio Kanban: received->diagnosis->repair->ready->delivered - Garantias/RMA, alertas de reorden, multi-sucursal - Stubs BNPL (APLAZO) y ERP Sync (Aspel/Contpaqi) FASE 6: - Notificaciones automaticas: push/WhatsApp/email/in-app - Reportes de ahorro vs retail_price - Logistica + tracking: DHL, FedEx, Estafeta, 99min, Uber - API Publica: API keys, rate limiting, catalog search Migraciones: v1.9-v3.0 Tests: 93/93 pasando Backup: nexus_backup_20260427_045859.tar.gz
102 lines
2.8 KiB
Python
Executable File
102 lines
2.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# /home/Autopartes/pos/migrations/runner_master.py
|
|
"""Apply schema migrations to the master database (nexus_autoparts)."""
|
|
|
|
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
|
|
|
|
MIGRATIONS_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
# Master DB migration registry: version -> filename
|
|
MASTER_MIGRATIONS = {
|
|
'v1.6': 'v1.6_marketplace.sql',
|
|
}
|
|
|
|
|
|
def get_current_master_version():
|
|
"""Get current schema version of master DB."""
|
|
conn = get_master_conn()
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
CREATE TABLE IF NOT EXISTS master_schema_version (
|
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
version VARCHAR(20) NOT NULL DEFAULT 'v0.0',
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
)
|
|
""")
|
|
cur.execute("""
|
|
INSERT INTO master_schema_version (id, version)
|
|
VALUES (1, 'v0.0')
|
|
ON CONFLICT (id) DO NOTHING
|
|
""")
|
|
conn.commit()
|
|
cur.execute("SELECT version FROM master_schema_version WHERE id = 1")
|
|
version = cur.fetchone()[0]
|
|
cur.close()
|
|
conn.close()
|
|
return version
|
|
|
|
|
|
def apply_master_migration(version):
|
|
"""Apply a single migration to the master DB."""
|
|
filename = MASTER_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_master_conn()
|
|
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_master_migrations():
|
|
"""Apply pending migrations to master DB."""
|
|
current_version = get_current_master_version()
|
|
sorted_versions = sorted(MASTER_MIGRATIONS.keys())
|
|
|
|
print(f"Master DB current version: {current_version}")
|
|
print(f"Available migrations: {sorted_versions}")
|
|
|
|
for version in sorted_versions:
|
|
if version <= current_version:
|
|
continue
|
|
|
|
print(f" Applying {version}...", end=' ')
|
|
if apply_master_migration(version):
|
|
conn = get_master_conn()
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
INSERT INTO master_schema_version (id, version)
|
|
VALUES (1, %s)
|
|
ON CONFLICT (id) DO UPDATE SET version = %s, updated_at = NOW()
|
|
""", (version, version))
|
|
conn.commit()
|
|
cur.close()
|
|
conn.close()
|
|
print("OK")
|
|
else:
|
|
print("FAILED — stopping master migrations")
|
|
break
|
|
|
|
print("Done.")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
run_master_migrations()
|