116 lines
4.1 KiB
Python
116 lines
4.1 KiB
Python
"""
|
|
Helpers para construir respuestas de scan y commit (formato unificado).
|
|
"""
|
|
from typing import Dict, Any, List, Optional
|
|
|
|
|
|
ERRORS_PREVIEW_LIMIT = 100
|
|
SUMMARY_LIMIT = 10
|
|
|
|
|
|
def _summarize_reasons(items: List[Dict[str, Any]], key_name: str) -> List[Dict[str, Any]]:
|
|
counts: Dict[str, int] = {}
|
|
for item in items:
|
|
reason = str(item.get(key_name, "")).strip()
|
|
if not reason:
|
|
continue
|
|
counts[reason] = counts.get(reason, 0) + 1
|
|
ordered = sorted(counts.items(), key=lambda kv: kv[1], reverse=True)
|
|
return [{"reason": reason, "count": count} for reason, count in ordered[:SUMMARY_LIMIT]]
|
|
|
|
|
|
def scan_result(
|
|
job_id: str,
|
|
processed_rows: int,
|
|
error_count: int,
|
|
errors_detail: List[Dict[str, Any]],
|
|
total_rows_in_file: Optional[int] = None,
|
|
message: Optional[str] = None,
|
|
) -> Dict[str, Any]:
|
|
"""Respuesta de scan_file (waiting_confirmation).
|
|
Si total_rows_in_file no se pasa, se usa processed_rows como total (comportamiento anterior).
|
|
"""
|
|
total = total_rows_in_file if total_rows_in_file is not None else processed_rows
|
|
valid_rows = processed_rows - error_count
|
|
out: Dict[str, Any] = {
|
|
"status": "waiting_confirmation",
|
|
"job_id": job_id,
|
|
"total_rows": total,
|
|
"error_count": error_count,
|
|
"valid_rows": valid_rows,
|
|
# Para no saturar el front: devolvemos solo un preview.
|
|
# El detalle completo se descarga desde CSV usando el job_id.
|
|
"errors": errors_detail[:ERRORS_PREVIEW_LIMIT],
|
|
"error_summary": _summarize_reasons([e for e in errors_detail if not e.get("warning")], "msg"),
|
|
}
|
|
if message:
|
|
out["message"] = message
|
|
elif valid_rows == 0 and total > 0:
|
|
out["message"] = (
|
|
"Ninguna fila quedó libre de observaciones en el escaneo. "
|
|
"Revise el reporte de errores (incluye advertencias por línea), "
|
|
"complete catálogos (clientes/proveedores, transporte, conductores, etc.) "
|
|
"y vuelva a cargar, o descargue el CSV de errores para corregir el archivo."
|
|
)
|
|
return out
|
|
|
|
|
|
def commit_result(
|
|
status: str,
|
|
inserted: int,
|
|
skipped_invalid: int,
|
|
skipped_missing_fk: int,
|
|
skipped_duplicate: int,
|
|
skipped_details: List[Dict[str, Any]],
|
|
message: Optional[str] = None,
|
|
error: Optional[str] = None,
|
|
) -> Dict[str, Any]:
|
|
"""Respuesta de insert_valid_rows (finished / warning / failed)."""
|
|
out = {
|
|
"status": status,
|
|
"inserted": inserted,
|
|
"skipped_invalid": skipped_invalid,
|
|
"skipped_missing_fk": skipped_missing_fk,
|
|
"skipped_duplicate": skipped_duplicate,
|
|
"skipped_details": skipped_details,
|
|
"skipped_summary": _summarize_reasons(skipped_details, "reason"),
|
|
}
|
|
if message:
|
|
out["message"] = message
|
|
if error:
|
|
out["error"] = error
|
|
return out
|
|
|
|
|
|
def normalize_commit_status_payload(d: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""
|
|
Homogeneiza respuestas de commit CSV (finished / warning) al contrato usado por pedimentos:
|
|
inserted, updated, skipped_*, skipped_details, skipped_summary, critical_reference_gaps,
|
|
reference_state_ready. No modifica waiting_confirmation ni otros status.
|
|
"""
|
|
if not isinstance(d, dict):
|
|
return d
|
|
st = d.get("status")
|
|
if st not in ("finished", "warning"):
|
|
return d
|
|
out = dict(d)
|
|
out.setdefault("inserted", 0)
|
|
out.setdefault("updated", 0)
|
|
out.setdefault("skipped_invalid", 0)
|
|
out.setdefault("skipped_missing_fk", 0)
|
|
out.setdefault("skipped_duplicate", 0)
|
|
out.setdefault("skipped_missing_invoice", 0)
|
|
details = out.get("skipped_details")
|
|
if not isinstance(details, list):
|
|
out["skipped_details"] = []
|
|
else:
|
|
out["skipped_details"] = details
|
|
out.setdefault("critical_reference_gaps", 0)
|
|
if "reference_state_ready" not in out:
|
|
out["reference_state_ready"] = out.get("critical_reference_gaps", 0) == 0
|
|
if "skipped_summary" not in out:
|
|
out["skipped_summary"] = (
|
|
_summarize_reasons(out["skipped_details"], "reason") if out["skipped_details"] else []
|
|
)
|
|
return out
|