Files
Autoparts-DB/scripts/rollup_tenant_metrics.py
consultoria-as a386ca5b4a
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled
Mejoras de sesion: estabilizacion, IA, Nexus Yonke y marketplace B2B
- 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
2026-10-12 00:57:31 +00:00

102 lines
4.1 KiB
Python

#!/usr/bin/env python3
"""Daily business-metrics rollup for every tenant, into the master table
``tenant_metrics_daily``.
Creates the table idempotently (no tenant migration runner involved) and
upserts one row per tenant per day, so it is safe to re-run for the same date.
Usage:
python3 scripts/rollup_tenant_metrics.py # today, active tenants
python3 scripts/rollup_tenant_metrics.py --date 2026-10-03
python3 scripts/rollup_tenant_metrics.py --all # include inactive tenants
python3 scripts/rollup_tenant_metrics.py --days 30 # backfill last 30 days
python3 scripts/rollup_tenant_metrics.py --tenant tenant_capi_autopartes
python3 scripts/rollup_tenant_metrics.py --json
Exit code 0 on success, 2 when one or more tenants failed to roll up.
"""
import argparse
import json
import os
import sys
from datetime import date as date_cls
MANAGER_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "manager")
if MANAGER_DIR not in sys.path:
sys.path.insert(0, MANAGER_DIR)
from services import portfolio_service # noqa: E402
def _print_report(result, health_by_tenant):
print(f"Rollup {result['date_from']} → {result['date_to']} "
f"({result['days']} día(s)) — {result['rows_written']} filas, "
f"{len(result['tenants'])} tenants")
print(f"{'tenant':<34} {'rows':>5} {'ventas(hoy)':>11} {'MX$ hoy':>10} "
f"{'items':>8} {'fitment%':>8} {'health':>6}")
for t in result["tenants"]:
h = health_by_tenant.get(t["tenant_id"], {})
last = t.get("last") or {}
print(f"{t['db_name']:<34} {t['rows']:>5} "
f"{last.get('ventas_count', ''):>11} "
f"{last.get('ventas_total', ''):>10} "
f"{last.get('items_activos', ''):>8} "
f"{str(last.get('fitment_pct', '')):>8} "
f"{str(h.get('health_score', '')):>6}")
for e in result["errors"]:
print(f" ERROR {e['db_name']}: {e['error']}", file=sys.stderr)
print("\nHealth (último día):")
for t in result["tenants"]:
h = health_by_tenant.get(t["tenant_id"], {})
codes = ", ".join(s["code"] for s in h.get("signals", [])) or "-"
print(f" {t['db_name']:<34} {str(h.get('health_score')):>5} "
f"{h.get('band', ''):<9} [{codes}]")
def main():
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--date", help="last day of the range (YYYY-MM-DD, default today)")
parser.add_argument("--days", type=int, default=1,
help="number of days to roll up ending at --date (default 1)")
parser.add_argument("--all", action="store_true",
help="include inactive tenants (default: active only)")
parser.add_argument("--tenant", action="append", default=None,
help="restrict to a db_name or tenant id (repeatable)")
parser.add_argument("--json", action="store_true", help="print raw JSON")
args = parser.parse_args()
target = None
if args.date:
try:
target = date_cls.fromisoformat(args.date)
except ValueError:
parser.error(f"fecha inválida: {args.date} (usa YYYY-MM-DD)")
result = portfolio_service.run_rollup(
date=target,
days=max(1, args.days),
tenant_ids=args.tenant,
include_inactive=args.all,
)
# Attach the latest collected row + health per tenant for the report/JSON.
metrics = portfolio_service.get_tenant_metrics(days=14)
health_by_tenant = {t["tenant_id"]: t["health"] for t in metrics["tenants"]}
latest_metrics = {t["tenant_id"]: t.get("metrics") for t in metrics["tenants"]}
for t in result["tenants"]:
t["last"] = latest_metrics.get(t["tenant_id"])
t["health"] = health_by_tenant.get(t["tenant_id"])
if args.json:
print(json.dumps(result, indent=2, default=str))
else:
_print_report(result, health_by_tenant)
return 2 if result["errors"] else 0
if __name__ == "__main__":
sys.exit(main())