- F0 blindaje: Redis/Celery, pg_hba sin trust LAN, secretos a env 600, backups, webhook auth, jobs muertos - F1 caja: bugs POS, reembolsos al corte, apartados, CFDI, topes de descuento en cotizacion/apartado - F2/F7 IA de catalogo: autocategorizacion, dedup de SKUs con embeddings, OCR de facturas, descripciones, claves SAT, limpieza de fitment - F3 IA en el flujo: vision Yonke, preguntas MeLi, venta cruzada, anomalias, sinonimos, busqueda semantica (rerank/embeddings) - F4/F8 escala y cartera: /metrics+Prometheus+Grafana, pool, score de credito, churn, metricas multi-tenant - Nexus Yonke (M1-M6): modelo de datos 1-de-1, alta por donador, vitrina publica, MeLi usado, consignacion, garantia por dias, reportes, etiquetas - Marketplace B2B entre yonkes (catalogo + pedidos cross-tenant) - Seguridad: auth en /api/admin/* (35 endpoints), alertas por tenant - Migraciones v4.27/v4.28; timers expire-demos y rollup-metrics
49 lines
1.4 KiB
Python
49 lines
1.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Run MercadoLibre sync (stock/price + orders) for all enabled tenants.
|
|
|
|
Called by systemd timer every 15 minutes. Runs the Celery task bodies
|
|
synchronously in-process (no broker needed from the timer context).
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'pos'))
|
|
|
|
import psycopg2 # noqa: E402
|
|
|
|
MASTER_DB = os.environ.get('MASTER_DB_NAME', 'nexus_autoparts')
|
|
|
|
|
|
def main():
|
|
conn = psycopg2.connect(dbname=MASTER_DB)
|
|
cur = conn.cursor()
|
|
cur.execute("""
|
|
SELECT t.id FROM tenants t
|
|
JOIN tenant_schema_version v ON v.tenant_id = t.id
|
|
WHERE t.is_active
|
|
ORDER BY t.id
|
|
""")
|
|
tenant_ids = [r[0] for r in cur.fetchall()]
|
|
cur.close()
|
|
conn.close()
|
|
|
|
from tasks import sync_meli_stock_price_task, sync_meli_orders_task
|
|
|
|
for tid in tenant_ids:
|
|
try:
|
|
r1 = sync_meli_stock_price_task.run(tid)
|
|
r2 = sync_meli_orders_task.run(tid)
|
|
print(f'[tenant {tid}] stock={r1} orders={r2}', flush=True)
|
|
except Exception as e:
|
|
# Meli disabled / not connected for this tenant is the common case
|
|
msg = str(e)
|
|
if 'not configured' in msg or 'not connected' in msg:
|
|
continue
|
|
print(f'[tenant {tid}] ERROR: {msg[:200]}', flush=True)
|
|
print('MeLi sync round complete.', flush=True)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|