feat: sistema de 3 estados (success/warning/error) para envíos TNS
- _parse_tns_resp retorna 'success'|'warning'|'error' en lugar de bool - 'ya existe/registrado/autorización' → warning (sin reenvío, no es error real) - errores reales → error (con reenvío) - Guarda JSON crudo completo en respuesta_api - logs.html: badge amarillo para warning, verde para success, rojo para error - Filtro de historial incluye opción 'warning' - reenvío en logs.py solo disponible para status='error' - reenvío en logs.py usa misma lógica _parse_tns_resp y soporta ventas Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
a37c1bb7d6
commit
6a452cd950
+12
-21
@@ -8,6 +8,7 @@ from app.auth import get_current_user
|
||||
from app.services.json_generator import _clean_times
|
||||
from app.services.api_client import get_tns_token, TNS_BASE
|
||||
from app.utils.activity import log_activity, get_ip
|
||||
from app.routes.automation import _parse_tns_resp
|
||||
|
||||
router = APIRouter(prefix="/logs", tags=["logs"])
|
||||
|
||||
@@ -144,8 +145,8 @@ async def reenviar_envio(envio_id: int, request: Request, user: dict = Depends(g
|
||||
conn.close()
|
||||
if not row:
|
||||
return JSONResponse({"success": False, "message": "Registro no encontrado"})
|
||||
if row["status"] == "success":
|
||||
return JSONResponse({"success": False, "message": "Ya fue enviado exitosamente"})
|
||||
if row["status"] in ("success", "warning"):
|
||||
return JSONResponse({"success": False, "message": "No aplica reenvío para este registro"})
|
||||
if not row["json_enviado"]:
|
||||
return JSONResponse({"success": False, "message": "Sin JSON guardado para reenviar"})
|
||||
|
||||
@@ -170,42 +171,32 @@ async def reenviar_envio(envio_id: int, request: Request, user: dict = Depends(g
|
||||
endpoint = (
|
||||
f"{TNS_BASE}/v2/rda/RdaPaciente/Insertar?codigosucursal={api_sucursal}"
|
||||
if tipo == "transaccion"
|
||||
else f"{TNS_BASE}/v2/facturacion/Ventas/Crear?codigosucursal={api_sucursal}"
|
||||
if tipo == "ventas"
|
||||
else f"{TNS_BASE}/v2/tablas/Tercero/Crear"
|
||||
)
|
||||
|
||||
ok = False
|
||||
new_status = "error"
|
||||
msg = ""
|
||||
raw_resp = ""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=30) as client:
|
||||
r = await client.post(endpoint, json=rda_json, headers=headers)
|
||||
raw_resp = r.text
|
||||
try:
|
||||
data = r.json()
|
||||
if tipo == "transaccion":
|
||||
ok = bool(data.get("status") or (data.get("data") or {}).get("success", False))
|
||||
msg = ((data.get("data") or {}).get("response") or data.get("message") or raw_resp[:300])
|
||||
else:
|
||||
ok = r.is_success
|
||||
msg = data.get("message", "") or raw_resp[:200]
|
||||
except Exception:
|
||||
ok = r.status_code < 300
|
||||
msg = raw_resp[:300]
|
||||
new_status, msg = _parse_tns_resp(r)
|
||||
except Exception as ex:
|
||||
msg = str(ex)
|
||||
|
||||
if ok:
|
||||
if new_status != "error":
|
||||
conn = get_connection()
|
||||
conn.execute(
|
||||
"UPDATE envios SET status='success', mensaje_tns=?, respuesta_api=?, created_at=? WHERE id=?",
|
||||
(msg, raw_resp[:2000], datetime.now().isoformat(), envio_id)
|
||||
"UPDATE envios SET status=?, mensaje_tns=?, respuesta_api=?, created_at=? WHERE id=?",
|
||||
(new_status, msg[:500], msg[:5000], datetime.now().isoformat(), envio_id)
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
log_activity(user["user_id"], user["username"], "reenvio_ok",
|
||||
f"Envío #{envio_id} factura {row['factura']} reenvío exitoso", get_ip(request))
|
||||
f"Envío #{envio_id} factura {row['factura']} reenvío {new_status}", get_ip(request))
|
||||
|
||||
return JSONResponse({"success": ok, "message": msg})
|
||||
return JSONResponse({"success": new_status != "error", "message": msg})
|
||||
|
||||
|
||||
@router.get("/detalle/{envio_id}")
|
||||
|
||||
Reference in New Issue
Block a user