diff --git a/app/routes/automation.py b/app/routes/automation.py index 84d7a85..4ee4c3d 100644 --- a/app/routes/automation.py +++ b/app/routes/automation.py @@ -177,6 +177,79 @@ WHERE r.FECHA_RECEPCION BETWEEN :fecha_ini AND :fecha_fin ORDER BY r.IDRECEPCION """ +_SQL_RDA_BY_ID = """ +SELECT + r.IDRECEPCION, r.PREFIJO, r.NUM_FACTURA, r.FECHA_RECEPCION, + r.COD_PACIENTE, r.NIT_EMPRESA, r.DIAG_PPAL, r.TIPOUSU, r.TIPOUSUSISPRO, + r.AUTORIZACION, r.CLASEPROC, r.HORAINICIORECEPCION, r.VALORTOTAL, r.VALORDESC, + rel.COD_EXAMEN, + COALESCE(NULLIF(TRIM(ex.NUM_ISS), ''), TRIM(rel.COD_EXAMEN)) AS CUPS, + rel.PRECIO, COALESCE(t.VALOR, rel.PRECIO) AS PRECIO_TARIFA, + rel.FECHA_REPORTADO, m.COD_ESPECIALIDAD, + COALESCE(NULLIF(TRIM(m.CODIGO), ''), NULLIF(TRIM(r.USUARIO), ''), '') AS profesional, + e.CODCONTRATO, TRIM(m.DOCIDMEDICO) AS DOCIDMEDICO +FROM RECEPCION r +JOIN RELACION rel ON rel.IDRECEPCION = r.IDRECEPCION +LEFT JOIN EXAMEN ex ON TRIM(ex.CODIGO) = TRIM(rel.COD_EXAMEN) +LEFT JOIN MEDICO m ON m.CODIGO = r.COD_MEDICO +LEFT JOIN EMPRESA e ON e.NIT = r.NIT_EMPRESA +LEFT JOIN TARIFA t ON TRIM(t.COD_EXAMEN) = TRIM(rel.COD_EXAMEN) AND t.TARIFA = e.TARIFA +WHERE r.IDRECEPCION = :idrecepcion +ORDER BY rel.COD_EXAMEN +""" + +_SQL_PRESERV_BY_ID = """ +SELECT + ps.ID_PS, ps.PS_PREFIJO, ps.PS_NUMERO, + r.IDRECEPCION, r.FECHA_RECEPCION, r.COD_PACIENTE, r.NIT_EMPRESA, + r.DIAG_PPAL, r.TIPOUSU, r.TIPOUSUSISPRO, r.AUTORIZACION, + r.CLASEPROC, r.HORAINICIORECEPCION, r.VALORTOTAL, r.VALORDESC, + COALESCE((SELECT FIRST 1 pg.VALOR FROM PAGOS pg + WHERE pg.NUMRECEP = r.IDRECEPCION AND pg.ESINICIAL = 'T'), 0) AS COPAGO, + rel.COD_EXAMEN, + COALESCE(NULLIF(TRIM(ex.NUM_ISS), ''), TRIM(rel.COD_EXAMEN)) AS CUPS, + rel.PRECIO, COALESCE(t.VALOR, rel.PRECIO) AS PRECIO_TARIFA, + rel.FECHA_REPORTADO, m.COD_ESPECIALIDAD, + COALESCE(NULLIF(TRIM(m.CODIGO), ''), NULLIF(TRIM(r.USUARIO), ''), '') AS profesional, + e.CODCONTRATO, TRIM(m.DOCIDMEDICO) AS DOCIDMEDICO +FROM PRESSERV_DIAN ps +JOIN RECEPCION r ON r.IDRECEPCION = ps.ID_RECEP +JOIN RELACION rel ON rel.IDRECEPCION = r.IDRECEPCION +LEFT JOIN EXAMEN ex ON TRIM(ex.CODIGO) = TRIM(rel.COD_EXAMEN) +LEFT JOIN MEDICO m ON m.CODIGO = r.COD_MEDICO +LEFT JOIN EMPRESA e ON e.NIT = r.NIT_EMPRESA +LEFT JOIN TARIFA t ON TRIM(t.COD_EXAMEN) = TRIM(rel.COD_EXAMEN) AND t.TARIFA = e.TARIFA +WHERE ps.ID_PS = :id_ps + AND (ps.PS_ANULADA IS NULL OR ps.PS_ANULADA = 'F') +ORDER BY rel.COD_EXAMEN +""" + +_SQL_VENTAS_BY_ID = """ +SELECT + r.IDRECEPCION, r.PREFIJO, r.NUM_FACTURA, r.FECHA_RECEPCION, + r.COD_PACIENTE, r.NIT_EMPRESA, r.VALORTOTAL, r.VALORDESC, + rel.COD_EXAMEN, + COALESCE(NULLIF(TRIM(ex.NUM_ISS), ''), TRIM(rel.COD_EXAMEN)) AS CUPS, + rel.PRECIO, COALESCE(t.VALOR, rel.PRECIO) AS PRECIO_TARIFA, + TRIM(e.CODCONTRATO) AS CODCONTRATO +FROM RECEPCION r +JOIN RELACION rel ON rel.IDRECEPCION = r.IDRECEPCION +LEFT JOIN EXAMEN ex ON TRIM(ex.CODIGO) = TRIM(rel.COD_EXAMEN) +LEFT JOIN EMPRESA e ON e.NIT = r.NIT_EMPRESA +LEFT JOIN TARIFA t ON TRIM(t.COD_EXAMEN) = TRIM(rel.COD_EXAMEN) AND t.TARIFA = e.TARIFA +WHERE r.IDRECEPCION = :idrecepcion +""" + +_SQL_PAC_BY_CODIGO = """ +SELECT + p.CODIGO, p.TIPOIDENT, p.DOCIDENT, p.NOMBRES, p.APELLIDOS, + p.DIRECCION, p.CIUDAD AS COD_CIUDAD, c.NOMBRE AS NOM_CIUDAD, + p.TELEFONOS, p.EMAIL, p.F_NACIMIENTO, p.SEXO, p.TIPORES, p.CODETNIA +FROM PACIENTE p +LEFT JOIN CIUDAD c ON c.CODIGO = p.CIUDAD +WHERE p.CODIGO = :codigo +""" + def _agrupar_por_presserv(rows: list) -> dict: """Agrupa filas de pre-servicios por ID_PS.""" @@ -417,6 +490,7 @@ async def run_automation( user: dict = Depends(get_current_user), fecha: str = Form(...), contrato: str = Form(""), + pasos: str = Form("terceros,rda,preserv,ventas"), ): conn = get_connection() configs = {row["key"]: row["value"] for row in conn.execute("SELECT * FROM config").fetchall()} @@ -484,8 +558,10 @@ async def run_automation( api_sucursal = configs.get("api_sucursal", "") timeout = int(configs.get("api_timeout", 30)) + pasos_set = {p.strip() for p in pasos.split(",")} resultado = { "fecha": fecha, + "pasos": list(pasos_set), "paso1_terceros": {"enviados": 0, "errores": 0, "detalle": []}, "paso2_rda": {"enviados": 0, "errores": 0, "detalle": []}, "paso3_preserv": {"enviados": 0, "errores": 0, "detalle": []}, @@ -493,37 +569,39 @@ async def run_automation( } # ── PASO 1: Enviar Terceros (particulares + EPS) ───────────────────────── - async with httpx.AsyncClient(timeout=timeout) as client: - for row in rows_pac_todos: - tercero_json = generar_tercero_api(row) - doc = tercero_json["nit"] - nombre = tercero_json["nombre"] - try: - resp = await client.post( - f"{TNS_BASE}/v2/tablas/Tercero/Crear", - json=tercero_json, headers=headers, - ) - ok = resp.is_success - msg = resp.json().get("message", "") if ok else resp.text[:200] - except Exception as e: - ok = False - msg = str(e) + if "terceros" in pasos_set: + async with httpx.AsyncClient(timeout=timeout) as client: + for row in rows_pac_todos: + tercero_json = generar_tercero_api(row) + doc = tercero_json["nit"] + nombre = tercero_json["nombre"] + codigo_pac = str(row.get("CODIGO", "")) + try: + resp = await client.post( + f"{TNS_BASE}/v2/tablas/Tercero/Crear", + json=tercero_json, headers=headers, + ) + ok = resp.is_success + msg = resp.json().get("message", "") if ok else resp.text[:200] + except Exception as e: + ok = False + msg = str(e) - if ok: - resultado["paso1_terceros"]["enviados"] += 1 - else: - resultado["paso1_terceros"]["errores"] += 1 + if ok: + resultado["paso1_terceros"]["enviados"] += 1 + else: + resultado["paso1_terceros"]["errores"] += 1 - resultado["paso1_terceros"]["detalle"].append({ - "doc": doc, "nombre": nombre, "ok": ok, "msg": msg, - }) + resultado["paso1_terceros"]["detalle"].append({ + "codigo": codigo_pac, "doc": doc, "nombre": nombre, "ok": ok, "msg": msg, + }) - _guardar_envio(user["user_id"], "terceros", fecha, tercero_json, msg, ok) + _guardar_envio(user["user_id"], "terceros", fecha, tercero_json, msg, ok) # ── Sync paralelo a WhatsApp Lab (silencioso) ───────────────────────────── wa_url = configs.get("whatsapp_url", "").rstrip("/") wa_key = configs.get("whatsapp_api_key", "") - if wa_url and wa_key and rows_pac: + if "terceros" in pasos_set and wa_url and wa_key and rows_pac: ingest_url = f"{wa_url}/api/lab/ingest_paciente.php" try: wa_resultado = await sync_todos(rows_pac, ingest_url, wa_key, timeout, modo="upsert") @@ -546,35 +624,37 @@ async def run_automation( prefijo_def = configs.get("prefijo_tns_default", "00") contrato_map = load_contrato_map() - async with httpx.AsyncClient(timeout=timeout) as client: - for id_recepcion, grupo_rows in grupos.items(): - num_fac = str(grupo_rows[0].get("NUM_FACTURA") or "").strip() - num_override = num_fac - rda_json = generar_rda_paciente(grupo_rows, prof_def, esp_def, remis_def, prefijo_def, num_override, contrato_map=contrato_map, sin_contrato_set=sin_contrato_set) - factura = num_override or str(id_recepcion) - try: - resp = await client.post(endpoint, json=rda_json, headers=headers) - ok = resp.is_success - msg = resp.json().get("message", "") if ok else resp.text[:200] - except Exception as e: - ok = False - msg = str(e) + if "rda" in pasos_set: + async with httpx.AsyncClient(timeout=timeout) as client: + for id_recepcion, grupo_rows in grupos.items(): + num_fac = str(grupo_rows[0].get("NUM_FACTURA") or "").strip() + num_override = num_fac + rda_json = generar_rda_paciente(grupo_rows, prof_def, esp_def, remis_def, prefijo_def, num_override, contrato_map=contrato_map, sin_contrato_set=sin_contrato_set) + factura = num_override or str(id_recepcion) + try: + resp = await client.post(endpoint, json=rda_json, headers=headers) + ok = resp.is_success + msg = resp.json().get("message", "") if ok else resp.text[:200] + except Exception as e: + ok = False + msg = str(e) - if ok: - resultado["paso2_rda"]["enviados"] += 1 - else: - resultado["paso2_rda"]["errores"] += 1 + if ok: + resultado["paso2_rda"]["enviados"] += 1 + else: + resultado["paso2_rda"]["errores"] += 1 - resultado["paso2_rda"]["detalle"].append({ - "factura": factura, - "paciente": str(grupo_rows[0].get("COD_PACIENTE", "")), - "examenes": len(grupo_rows), - "ok": ok, "msg": msg, - }) + resultado["paso2_rda"]["detalle"].append({ + "idrecepcion": id_recepcion, + "factura": factura, + "paciente": str(grupo_rows[0].get("COD_PACIENTE", "")), + "examenes": len(grupo_rows), + "ok": ok, "msg": msg, + }) - _guardar_envio(user["user_id"], "transaccion", factura, rda_json, msg, ok, - fecha_inicio=fecha, fecha_fin=fecha, - servicios=len(grupo_rows)) + _guardar_envio(user["user_id"], "transaccion", factura, rda_json, msg, ok, + fecha_inicio=fecha, fecha_fin=fecha, + servicios=len(grupo_rows)) # ── PASO 3: Enviar Pre-servicios (RCXC / SC) ────────────────────────────── grupos_ps_all = _agrupar_por_presserv(rows_ps) @@ -582,41 +662,43 @@ async def run_automation( if str(v[0].get("CODCONTRATO") or "").strip() not in excluded} resultado["paso3_preserv"]["excluidos"] = len(grupos_ps_all) - len(grupos_ps) - async with httpx.AsyncClient(timeout=timeout) as client: - for id_ps, grupo_rows in grupos_ps.items(): - ps_prefijo = str(grupo_rows[0].get("PS_PREFIJO") or "SC").strip() - ps_numero = str(grupo_rows[0].get("PS_NUMERO") or "").strip() - rda_json = generar_rda_paciente( - grupo_rows, prof_def, esp_def, remis_def, prefijo_def, - numero_override=ps_numero, - contrato_map=contrato_map, - prefijo_override="00" if ps_prefijo == "RCXC" else ps_prefijo, - sin_contrato_set=sin_contrato_set, - ) - factura_ps = f"{ps_prefijo}-{ps_numero.zfill(5)}" - try: - resp = await client.post(endpoint, json=rda_json, headers=headers) - ok = resp.is_success - msg = resp.json().get("message", "") if ok else resp.text[:200] - except Exception as e: - ok = False - msg = str(e) + if "preserv" in pasos_set: + async with httpx.AsyncClient(timeout=timeout) as client: + for id_ps, grupo_rows in grupos_ps.items(): + ps_prefijo = str(grupo_rows[0].get("PS_PREFIJO") or "SC").strip() + ps_numero = str(grupo_rows[0].get("PS_NUMERO") or "").strip() + rda_json = generar_rda_paciente( + grupo_rows, prof_def, esp_def, remis_def, prefijo_def, + numero_override=ps_numero, + contrato_map=contrato_map, + prefijo_override="00" if ps_prefijo == "RCXC" else ps_prefijo, + sin_contrato_set=sin_contrato_set, + ) + factura_ps = f"{ps_prefijo}-{ps_numero.zfill(5)}" + try: + resp = await client.post(endpoint, json=rda_json, headers=headers) + ok = resp.is_success + msg = resp.json().get("message", "") if ok else resp.text[:200] + except Exception as e: + ok = False + msg = str(e) - if ok: - resultado["paso3_preserv"]["enviados"] += 1 - else: - resultado["paso3_preserv"]["errores"] += 1 + if ok: + resultado["paso3_preserv"]["enviados"] += 1 + else: + resultado["paso3_preserv"]["errores"] += 1 - resultado["paso3_preserv"]["detalle"].append({ - "factura": factura_ps, - "paciente": str(grupo_rows[0].get("COD_PACIENTE", "")), - "examenes": len(grupo_rows), - "ok": ok, "msg": msg, - }) + resultado["paso3_preserv"]["detalle"].append({ + "idrecepcion": id_ps, + "factura": factura_ps, + "paciente": str(grupo_rows[0].get("COD_PACIENTE", "")), + "examenes": len(grupo_rows), + "ok": ok, "msg": msg, + }) - _guardar_envio(user["user_id"], "transaccion", factura_ps, rda_json, msg, ok, - fecha_inicio=fecha, fecha_fin=fecha, - servicios=len(grupo_rows)) + _guardar_envio(user["user_id"], "transaccion", factura_ps, rda_json, msg, ok, + fecha_inicio=fecha, fecha_fin=fecha, + servicios=len(grupo_rows)) # ── PASO 4: Enviar Facturas Venta ───────────────────────────────────────── excluded_ventas = load_excluded_ventas_set() @@ -626,37 +708,39 @@ async def run_automation( resultado["paso4_ventas"]["excluidos"] = len(grupos_vta_all) - len(grupos_vta) endpoint_venta = f"{TNS_BASE}/v2/facturacion/Ventas/Crear" - async with httpx.AsyncClient(timeout=timeout) as client: - for id_rec, 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() - try: - resp = await client.post(endpoint_venta, json=venta_json, headers=headers) - ok = resp.is_success - msg = resp.json().get("message", "") if ok else resp.text[:200] - except Exception as e: - ok = False - msg = str(e) + if "ventas" in pasos_set: + async with httpx.AsyncClient(timeout=timeout) as client: + for id_rec, 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() + try: + resp = await client.post(endpoint_venta, json=venta_json, headers=headers) + ok = resp.is_success + msg = resp.json().get("message", "") if ok else resp.text[:200] + except Exception as e: + ok = False + msg = str(e) - if ok: - resultado["paso4_ventas"]["enviados"] += 1 - else: - resultado["paso4_ventas"]["errores"] += 1 + if ok: + resultado["paso4_ventas"]["enviados"] += 1 + else: + resultado["paso4_ventas"]["errores"] += 1 - resultado["paso4_ventas"]["detalle"].append({ - "factura": factura_display, - "paciente": str(grupo_rows[0].get("COD_PACIENTE", "")), - "examenes": len(grupo_rows), - "ok": ok, "msg": msg, - }) + resultado["paso4_ventas"]["detalle"].append({ + "idrecepcion": id_rec, + "factura": factura_display, + "paciente": str(grupo_rows[0].get("COD_PACIENTE", "")), + "examenes": len(grupo_rows), + "ok": ok, "msg": msg, + }) - _guardar_envio(user["user_id"], "ventas", factura_display, venta_json, msg, ok, - fecha_inicio=fecha, fecha_fin=fecha, servicios=len(grupo_rows), - idrecepcion=id_rec, contrato=contrato_vta) + _guardar_envio(user["user_id"], "ventas", factura_display, venta_json, msg, ok, + fecha_inicio=fecha, fecha_fin=fecha, servicios=len(grupo_rows), + idrecepcion=id_rec, contrato=contrato_vta) r1 = resultado["paso1_terceros"] r2 = resultado["paso2_rda"] @@ -694,3 +778,189 @@ def _guardar_envio(user_id, tipo, factura, json_data, respuesta, ok, conn.close() except Exception: pass + + +@router.post("/reenviar-tercero") +async def reenviar_tercero( + request: Request, + user: dict = Depends(get_current_user), + codigo: str = Form(...), +): + conn = get_connection() + configs = {row["key"]: row["value"] for row in conn.execute("SELECT * FROM config").fetchall()} + conn.close() + + fb, fb_ok, fb_msg = get_firebird_from_config(configs) + if not fb_ok: + return JSONResponse({"success": False, "message": f"Error Firebird: {fb_msg}"}) + + ok, err, rows = fb.execute_query(_SQL_PAC_BY_CODIGO, {"codigo": codigo.strip()}) + fb.disconnect() + + if not ok or not rows: + return JSONResponse({"success": False, "message": err or "Paciente no encontrado"}) + + tercero_json = generar_tercero_api(dict(rows[0])) + token, token_err = await get_tns_token( + configs.get("tns_empresa", ""), configs.get("tns_usuario", ""), configs.get("tns_password", "") + ) + if not token: + return JSONResponse({"success": False, "message": f"Token TNS: {token_err}"}) + + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"} + try: + async with httpx.AsyncClient(timeout=int(configs.get("api_timeout", 30))) as client: + resp = await client.post(f"{TNS_BASE}/v2/tablas/Tercero/Crear", json=tercero_json, headers=headers) + ok_r = resp.is_success + msg = resp.json().get("message", "") if ok_r else resp.text[:200] + except Exception as e: + ok_r = False + msg = str(e) + + _guardar_envio(user["user_id"], "terceros", codigo, tercero_json, msg, ok_r) + return JSONResponse({"success": ok_r, "message": msg}) + + +@router.post("/reenviar-rda") +async def reenviar_rda( + request: Request, + user: dict = Depends(get_current_user), + idrecepcion: int = Form(...), + tipo: str = Form("rda"), +): + conn = get_connection() + configs = {row["key"]: row["value"] for row in conn.execute("SELECT * FROM config").fetchall()} + conn.close() + + fb, fb_ok, fb_msg = get_firebird_from_config(configs) + if not fb_ok: + return JSONResponse({"success": False, "message": f"Error Firebird: {fb_msg}"}) + + if tipo == "preserv": + ok, err, rows = fb.execute_query(_SQL_PRESERV_BY_ID, {"id_ps": idrecepcion}) + else: + ok, err, rows = fb.execute_query(_SQL_RDA_BY_ID, {"idrecepcion": idrecepcion}) + fb.disconnect() + + if not ok or not rows: + return JSONResponse({"success": False, "message": err or "Sin datos"}) + + excluded = load_excluded_set() + contrato = str(rows[0].get("CODCONTRATO") or "").strip() + if contrato in excluded: + return JSONResponse({"success": False, "message": f"Contrato {contrato} excluido"}) + + prof_def = configs.get("profesional_default", "") + esp_def = configs.get("especialidad_default", "") + remis_def = configs.get("remisionante_default", "00") + prefijo_def = configs.get("prefijo_tns_default", "00") + contrato_map = load_contrato_map() + sin_contrato_set = load_sin_contrato_set() + api_sucursal = configs.get("api_sucursal", "") or "00" + + if tipo == "preserv": + from collections import defaultdict + grupos_ps: dict = defaultdict(list) + for row in rows: + grupos_ps[row.get("ID_PS")].append(dict(row)) + grupo_rows = list(grupos_ps.values())[0] + ps_prefijo = str(grupo_rows[0].get("PS_PREFIJO") or "SC").strip() + ps_numero = str(grupo_rows[0].get("PS_NUMERO") or "").strip() + rda_json = generar_rda_paciente( + grupo_rows, prof_def, esp_def, remis_def, prefijo_def, + numero_override=ps_numero, contrato_map=contrato_map, + prefijo_override="00" if ps_prefijo == "RCXC" else ps_prefijo, + sin_contrato_set=sin_contrato_set, + ) + factura = f"{ps_prefijo}-{ps_numero.zfill(5)}" + else: + grupos = agrupar_por_recepcion(rows) + grupo_rows = list(grupos.values())[0] + num_fac = str(grupo_rows[0].get("NUM_FACTURA") or "").strip() + rda_json = generar_rda_paciente( + grupo_rows, prof_def, esp_def, remis_def, prefijo_def, + numero_override=num_fac, contrato_map=contrato_map, + sin_contrato_set=sin_contrato_set, + ) + factura = num_fac or str(idrecepcion) + + token, token_err = await get_tns_token( + configs.get("tns_empresa", ""), configs.get("tns_usuario", ""), configs.get("tns_password", "") + ) + if not token: + return JSONResponse({"success": False, "message": f"Token TNS: {token_err}"}) + + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"} + endpoint = f"{TNS_BASE}/v2/rda/RdaPaciente/Insertar?codigosucursal={api_sucursal}" + try: + async with httpx.AsyncClient(timeout=int(configs.get("api_timeout", 30))) as client: + resp = await client.post(endpoint, json=rda_json, headers=headers) + ok_r = resp.is_success + msg = resp.json().get("message", "") if ok_r else resp.text[:200] + except Exception as e: + ok_r = False + msg = str(e) + + _guardar_envio(user["user_id"], "transaccion", factura, rda_json, msg, ok_r, + idrecepcion=idrecepcion, contrato=contrato) + return JSONResponse({"success": ok_r, "message": msg}) + + +@router.post("/reenviar-venta") +async def reenviar_venta( + request: Request, + user: dict = Depends(get_current_user), + idrecepcion: int = Form(...), +): + conn = get_connection() + configs = {row["key"]: row["value"] for row in conn.execute("SELECT * FROM config").fetchall()} + conn.close() + + fb, fb_ok, fb_msg = get_firebird_from_config(configs) + if not fb_ok: + return JSONResponse({"success": False, "message": f"Error Firebird: {fb_msg}"}) + + ok, err, rows = fb.execute_query(_SQL_VENTAS_BY_ID, {"idrecepcion": idrecepcion}) + fb.disconnect() + + if not ok or not rows: + return JSONResponse({"success": False, "message": err or "Sin datos"}) + + excluded_ventas = load_excluded_ventas_set() + contrato_vta = str(rows[0].get("CODCONTRATO") or "").strip() + if contrato_vta in excluded_ventas: + return JSONResponse({"success": False, "message": f"Contrato {contrato_vta} excluido"}) + + from collections import defaultdict + grupos: dict = defaultdict(list) + for row in rows: + grupos[row.get("IDRECEPCION")].append(dict(row)) + grupo_rows = list(grupos.values())[0] + + prefijo_def = configs.get("prefijo_tns_default", "00") + 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}" + + token, token_err = await get_tns_token( + configs.get("tns_empresa", ""), configs.get("tns_usuario", ""), configs.get("tns_password", "") + ) + if not token: + return JSONResponse({"success": False, "message": f"Token TNS: {token_err}"}) + + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"} + endpoint = f"{TNS_BASE}/v2/facturacion/Ventas/Crear" + try: + async with httpx.AsyncClient(timeout=int(configs.get("api_timeout", 30))) as client: + resp = await client.post(endpoint, json=venta_json, headers=headers) + ok_r = resp.is_success + msg = resp.json().get("message", "") if ok_r else resp.text[:200] + except Exception as e: + ok_r = False + msg = str(e) + + _guardar_envio(user["user_id"], "ventas", factura_display, venta_json, msg, ok_r, + idrecepcion=idrecepcion, contrato=contrato_vta) + return JSONResponse({"success": ok_r, "message": msg}) diff --git a/app/templates/automation.html b/app/templates/automation.html index cb44b18..e30c25c 100644 --- a/app/templates/automation.html +++ b/app/templates/automation.html @@ -4,82 +4,108 @@ {% block content %}
- +

Envío automático por fecha

- Selecciona una fecha para ver cuántos pacientes y RDA se enviarán a TNS. + Selecciona fecha, pasos activos y convenio (opcional) para enviar a TNS.

-
-
-
+
+ +
+
- +
- - +
+ + +
+ Pasos: + + + +
- +