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
This commit is contained in:
48
manager/blueprints/portfolio_bp.py
Normal file
48
manager/blueprints/portfolio_bp.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""Portfolio operations blueprint: business metrics, health and anomalies.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
``GET /api/tenants/metrics`` rollup window + health score per tenant
|
||||
``GET /api/portfolio/anomalies`` cross-tenant anomalies (median + MAD z-score)
|
||||
"""
|
||||
from datetime import date as date_cls
|
||||
|
||||
from flask import Blueprint, jsonify, request
|
||||
from services import portfolio_service
|
||||
|
||||
from blueprints.auth_bp import require_manager_auth
|
||||
|
||||
portfolio_bp = Blueprint("portfolio", __name__, url_prefix="/api")
|
||||
|
||||
|
||||
@portfolio_bp.route("/tenants/metrics", methods=["GET"])
|
||||
@require_manager_auth
|
||||
def tenant_metrics():
|
||||
days = request.args.get("days", 14, type=int)
|
||||
include_inactive = request.args.get("all", "false").lower() == "true"
|
||||
return jsonify(portfolio_service.get_tenant_metrics(
|
||||
days=days, include_inactive=include_inactive))
|
||||
|
||||
|
||||
@portfolio_bp.route("/portfolio/anomalies", methods=["GET"])
|
||||
@require_manager_auth
|
||||
def portfolio_anomalies():
|
||||
target = request.args.get("date")
|
||||
if target:
|
||||
try:
|
||||
date_cls.fromisoformat(target)
|
||||
except ValueError:
|
||||
return jsonify({"error": "date must be YYYY-MM-DD"}), 400
|
||||
|
||||
kwargs = {
|
||||
"date": target,
|
||||
"include_inactive": request.args.get("all", "false").lower() == "true",
|
||||
}
|
||||
z = request.args.get("z", type=float)
|
||||
if z is not None:
|
||||
kwargs["z_threshold"] = z
|
||||
min_tenants = request.args.get("min_tenants", type=int)
|
||||
if min_tenants is not None:
|
||||
kwargs["min_tenants"] = min_tenants
|
||||
|
||||
return jsonify(portfolio_service.get_portfolio_anomalies(**kwargs))
|
||||
Reference in New Issue
Block a user