fix: group ventas by NUM_FACTURA, not IDRECEPCION
A single CMXC invoice (e.g. CMXC-307) can have multiple receptions. Previously each reception was sent as a separate ventas, causing TNS to accept the first and reject the rest with "ya existe" — leaving only 1/N of the services registered. Now agrupar_por_factura groups all receptions sharing the same NUM_FACTURA into one ventas JSON with all their services in detallePedido. One factura = one send. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
531fb29122
commit
7f2dffc63e
@@ -11,6 +11,7 @@ from app.services.json_generator import (
|
|||||||
generar_tercero_api,
|
generar_tercero_api,
|
||||||
generar_rda_paciente,
|
generar_rda_paciente,
|
||||||
agrupar_por_recepcion,
|
agrupar_por_recepcion,
|
||||||
|
agrupar_por_factura,
|
||||||
generar_factura_venta,
|
generar_factura_venta,
|
||||||
)
|
)
|
||||||
from app.services.api_client import get_tns_token, TNS_BASE
|
from app.services.api_client import get_tns_token, TNS_BASE
|
||||||
@@ -453,13 +454,13 @@ async def preview_automation(
|
|||||||
if rda_por_pac.get(str(p.get("CODIGO", "")))
|
if rda_por_pac.get(str(p.get("CODIGO", "")))
|
||||||
]
|
]
|
||||||
|
|
||||||
grupos_vta_all = agrupar_por_recepcion(rows_vta)
|
grupos_vta_all = agrupar_por_factura(rows_vta)
|
||||||
grupos_vta = {k: v for k, v in grupos_vta_all.items()
|
grupos_vta = {k: v for k, v in grupos_vta_all.items()
|
||||||
if str(v[0].get("CODCONTRATO") or "").strip() not in excluded_ventas
|
if str(v[0].get("CODCONTRATO") or "").strip() not in excluded_ventas
|
||||||
and int(v[0].get("NUM_FACTURA") or 0) != 0}
|
and int(v[0].get("NUM_FACTURA") or 0) != 0}
|
||||||
|
|
||||||
ventas_preview = []
|
ventas_preview = []
|
||||||
for id_rec, grupo_rows in grupos_vta.items():
|
for num_fac_key, grupo_rows in grupos_vta.items():
|
||||||
num_fac = str(grupo_rows[0].get("NUM_FACTURA") or "").strip()
|
num_fac = str(grupo_rows[0].get("NUM_FACTURA") or "").strip()
|
||||||
prefijo = str(grupo_rows[0].get("PREFIJO") or "").strip()
|
prefijo = str(grupo_rows[0].get("PREFIJO") or "").strip()
|
||||||
venta_json = generar_factura_venta(grupo_rows, default_vendedor="00",
|
venta_json = generar_factura_venta(grupo_rows, default_vendedor="00",
|
||||||
@@ -732,7 +733,7 @@ async def run_automation(
|
|||||||
|
|
||||||
# ── PASO 4: Enviar Facturas Venta ─────────────────────────────────────────
|
# ── PASO 4: Enviar Facturas Venta ─────────────────────────────────────────
|
||||||
excluded_ventas = load_excluded_ventas_set()
|
excluded_ventas = load_excluded_ventas_set()
|
||||||
grupos_vta_all = agrupar_por_recepcion(rows_vta)
|
grupos_vta_all = agrupar_por_factura(rows_vta)
|
||||||
grupos_vta = {k: v for k, v in grupos_vta_all.items()
|
grupos_vta = {k: v for k, v in grupos_vta_all.items()
|
||||||
if str(v[0].get("CODCONTRATO") or "").strip() not in excluded_ventas
|
if str(v[0].get("CODCONTRATO") or "").strip() not in excluded_ventas
|
||||||
and int(v[0].get("NUM_FACTURA") or 0) != 0}
|
and int(v[0].get("NUM_FACTURA") or 0) != 0}
|
||||||
@@ -741,13 +742,14 @@ async def run_automation(
|
|||||||
endpoint_venta = f"{TNS_BASE}/v2/facturacion/Ventas/Crear?codigosucursal={api_sucursal or '00'}"
|
endpoint_venta = f"{TNS_BASE}/v2/facturacion/Ventas/Crear?codigosucursal={api_sucursal or '00'}"
|
||||||
if "ventas" in pasos_set:
|
if "ventas" in pasos_set:
|
||||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||||
for id_rec, grupo_rows in grupos_vta.items():
|
for num_fac_key, grupo_rows in grupos_vta.items():
|
||||||
num_fac = str(grupo_rows[0].get("NUM_FACTURA") or "").strip()
|
num_fac = str(grupo_rows[0].get("NUM_FACTURA") or "").strip()
|
||||||
prefijo = str(grupo_rows[0].get("PREFIJO") or "").strip()
|
prefijo = str(grupo_rows[0].get("PREFIJO") or "").strip()
|
||||||
venta_json = generar_factura_venta(grupo_rows, default_vendedor="00",
|
venta_json = generar_factura_venta(grupo_rows, default_vendedor="00",
|
||||||
default_prefijo=prefijo_def, numero_override=num_fac)
|
default_prefijo=prefijo_def, numero_override=num_fac)
|
||||||
factura_display = f"{prefijo}-{num_fac}"
|
factura_display = f"{prefijo}-{num_fac}"
|
||||||
contrato_vta = str(grupo_rows[0].get("CODCONTRATO") or "").strip()
|
contrato_vta = str(grupo_rows[0].get("CODCONTRATO") or "").strip()
|
||||||
|
id_rec_display = str(grupo_rows[0].get("IDRECEPCION") or "")
|
||||||
try:
|
try:
|
||||||
resp = await client.post(endpoint_venta, json=venta_json, headers=headers)
|
resp = await client.post(endpoint_venta, json=venta_json, headers=headers)
|
||||||
status, msg = _parse_tns_resp(resp)
|
status, msg = _parse_tns_resp(resp)
|
||||||
@@ -760,7 +762,7 @@ async def run_automation(
|
|||||||
resultado["paso4_ventas"]["enviados"] += 1
|
resultado["paso4_ventas"]["enviados"] += 1
|
||||||
|
|
||||||
resultado["paso4_ventas"]["detalle"].append({
|
resultado["paso4_ventas"]["detalle"].append({
|
||||||
"idrecepcion": id_rec,
|
"idrecepcion": id_rec_display,
|
||||||
"factura": factura_display,
|
"factura": factura_display,
|
||||||
"paciente": str(grupo_rows[0].get("COD_PACIENTE", "")),
|
"paciente": str(grupo_rows[0].get("COD_PACIENTE", "")),
|
||||||
"examenes": len(grupo_rows),
|
"examenes": len(grupo_rows),
|
||||||
@@ -769,7 +771,7 @@ async def run_automation(
|
|||||||
|
|
||||||
_guardar_envio(user["user_id"], "ventas", factura_display, venta_json, msg, status,
|
_guardar_envio(user["user_id"], "ventas", factura_display, venta_json, msg, status,
|
||||||
fecha_inicio=fecha, fecha_fin=fecha, servicios=len(grupo_rows),
|
fecha_inicio=fecha, fecha_fin=fecha, servicios=len(grupo_rows),
|
||||||
idrecepcion=id_rec, contrato=contrato_vta,
|
idrecepcion=id_rec_display, contrato=contrato_vta,
|
||||||
cedula=pac_map.get(str(grupo_rows[0].get("COD_PACIENTE", "")), ""))
|
cedula=pac_map.get(str(grupo_rows[0].get("COD_PACIENTE", "")), ""))
|
||||||
|
|
||||||
r1 = resultado["paso1_terceros"]
|
r1 = resultado["paso1_terceros"]
|
||||||
|
|||||||
@@ -125,6 +125,15 @@ def agrupar_por_recepcion(rows: list) -> dict:
|
|||||||
return grupos
|
return grupos
|
||||||
|
|
||||||
|
|
||||||
|
def agrupar_por_factura(rows: list) -> dict:
|
||||||
|
"""Agrupa filas por NUM_FACTURA — para ventas CMXC donde una factura puede tener varias recepciones."""
|
||||||
|
grupos = defaultdict(list)
|
||||||
|
for row in rows:
|
||||||
|
key = str(row.get("NUM_FACTURA") or "")
|
||||||
|
grupos[key].append(dict(row))
|
||||||
|
return grupos
|
||||||
|
|
||||||
|
|
||||||
def generar_rda_paciente(rows: list, default_profesional: str = "", default_especialidad: str = "",
|
def generar_rda_paciente(rows: list, default_profesional: str = "", default_especialidad: str = "",
|
||||||
default_remisionante: str = "00", default_prefijo: str = "00",
|
default_remisionante: str = "00", default_prefijo: str = "00",
|
||||||
numero_override: str = "", contrato_map: dict = None,
|
numero_override: str = "", contrato_map: dict = None,
|
||||||
|
|||||||
Reference in New Issue
Block a user