From 7f2dffc63e2b6af36b16e963f2288ab9ea5af87f Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Mon, 27 Jul 2026 17:36:21 -0500 Subject: [PATCH] fix: group ventas by NUM_FACTURA, not IDRECEPCION MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- app/routes/automation.py | 14 ++++++++------ app/services/json_generator.py | 9 +++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/routes/automation.py b/app/routes/automation.py index 2554dca..412b435 100644 --- a/app/routes/automation.py +++ b/app/routes/automation.py @@ -11,6 +11,7 @@ from app.services.json_generator import ( generar_tercero_api, generar_rda_paciente, agrupar_por_recepcion, + agrupar_por_factura, generar_factura_venta, ) 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", ""))) ] - 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() if str(v[0].get("CODCONTRATO") or "").strip() not in excluded_ventas and int(v[0].get("NUM_FACTURA") or 0) != 0} 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() prefijo = str(grupo_rows[0].get("PREFIJO") or "").strip() venta_json = generar_factura_venta(grupo_rows, default_vendedor="00", @@ -732,7 +733,7 @@ async def run_automation( # ── PASO 4: Enviar Facturas Venta ───────────────────────────────────────── 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() if str(v[0].get("CODCONTRATO") or "").strip() not in excluded_ventas 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'}" if "ventas" in pasos_set: 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() prefijo = str(grupo_rows[0].get("PREFIJO") or "").strip() venta_json = generar_factura_venta(grupo_rows, default_vendedor="00", default_prefijo=prefijo_def, numero_override=num_fac) factura_display = f"{prefijo}-{num_fac}" contrato_vta = str(grupo_rows[0].get("CODCONTRATO") or "").strip() + id_rec_display = str(grupo_rows[0].get("IDRECEPCION") or "") try: resp = await client.post(endpoint_venta, json=venta_json, headers=headers) status, msg = _parse_tns_resp(resp) @@ -760,7 +762,7 @@ async def run_automation( resultado["paso4_ventas"]["enviados"] += 1 resultado["paso4_ventas"]["detalle"].append({ - "idrecepcion": id_rec, + "idrecepcion": id_rec_display, "factura": factura_display, "paciente": str(grupo_rows[0].get("COD_PACIENTE", "")), "examenes": len(grupo_rows), @@ -769,7 +771,7 @@ async def run_automation( _guardar_envio(user["user_id"], "ventas", factura_display, venta_json, msg, status, 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", "")), "")) r1 = resultado["paso1_terceros"] diff --git a/app/services/json_generator.py b/app/services/json_generator.py index e4b765b..731e2d9 100644 --- a/app/services/json_generator.py +++ b/app/services/json_generator.py @@ -125,6 +125,15 @@ def agrupar_por_recepcion(rows: list) -> dict: 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 = "", default_remisionante: str = "00", default_prefijo: str = "00", numero_override: str = "", contrato_map: dict = None,