diff --git a/app/database.py b/app/database.py index c5dfe49..5d61f0a 100644 --- a/app/database.py +++ b/app/database.py @@ -31,9 +31,14 @@ def _migrate(conn): nit_empresa TEXT NOT NULL DEFAULT '', tipo_usuario TEXT NOT NULL, descripcion TEXT NOT NULL DEFAULT '', + excluir INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) ) """) + else: + contrato_cols = {r[1] for r in conn.execute("PRAGMA table_info(contratos)")} + if "excluir" not in contrato_cols: + conn.execute("ALTER TABLE contratos ADD COLUMN excluir INTEGER NOT NULL DEFAULT 0") conn.commit() diff --git a/app/routes/automation.py b/app/routes/automation.py index abc796e..fb9c77c 100644 --- a/app/routes/automation.py +++ b/app/routes/automation.py @@ -14,7 +14,7 @@ from app.services.json_generator import ( ) from app.services.api_client import get_tns_token, TNS_BASE from app.services.whatsapp_sync import sync_paciente, sync_todos, guardar_sync_log -from app.routes.contratos import load_contrato_map +from app.routes.contratos import load_contrato_map, load_excluded_set router = APIRouter(prefix="/automation", tags=["automation"]) @@ -137,7 +137,11 @@ async def preview_automation( if not ok2: return JSONResponse({"success": False, "message": f"Error BD RDA: {err2}"}) - grupos = agrupar_por_recepcion(rows_rda) + grupos_all = agrupar_por_recepcion(rows_rda) + excluded = load_excluded_set() + grupos = {k: v for k, v in grupos_all.items() + if str(v[0].get("CODCONTRATO") or "").strip() not in excluded} + excluidos_count = len(grupos_all) - len(grupos) total_examenes = sum(len(v) for v in grupos.values()) # Agrupar RDA por COD_PACIENTE @@ -172,6 +176,7 @@ async def preview_automation( "pacientes": len(rows_pac), "recepciones": len(grupos), "examenes": total_examenes, + "excluidos": excluidos_count, "pacientes_preview": pacientes_preview, }) @@ -273,7 +278,12 @@ async def run_automation( pass # ── PASO 2: Enviar RDA Paciente ─────────────────────────────────────────── - grupos = agrupar_por_recepcion(rows_rda) + excluded = load_excluded_set() + grupos_all = agrupar_por_recepcion(rows_rda) + grupos = {k: v for k, v in grupos_all.items() + if str(v[0].get("CODCONTRATO") or "").strip() not in excluded} + resultado["paso2_rda"]["excluidos"] = len(grupos_all) - len(grupos) + endpoint = f"{TNS_BASE}/v2/rda/RdaPaciente/Insertar?codigosucursal={api_sucursal or '00'}" prof_def = configs.get("profesional_default", "") esp_def = configs.get("especialidad_default", "") diff --git a/app/routes/contratos.py b/app/routes/contratos.py index 6202d2f..f53bc64 100644 --- a/app/routes/contratos.py +++ b/app/routes/contratos.py @@ -5,37 +5,66 @@ from app.auth import get_current_user router = APIRouter(prefix="/contratos", tags=["contratos"]) +# (numero_contrato, nit_empresa, tipo_usuario, descripcion, excluir) _SEED = [ - ("001", "860078828", "11", "EPS SANITAS"), - ("002", "830054904", "11", "EPS COMPENSAR"), - ("003", "900278729", "12", "PARTICULAR"), - ("004", "800106339", "11", "EPS NUEVA EPS"), - ("005", "800153424", "11", "EPS SURA"), - ("006", "805009741", "11", "EPS COOMEVA"), - ("007", "860002183", "11", "EPS FAMISANAR"), - ("008", "860002503", "11", "EPS CRUZ BLANCA"), - ("009", "860027404", "11", "EPS COLSANITAS"), - ("010", "860039988", "11", "EPS SALUD TOTAL"), - ("011", "890903790", "11", "EPS SAVIA SALUD"), - ("012", "900178724", "11", "EPS MUTUAL SER"), - ("034", "860078828", "11", "EPS SANITAS (alt)"), - ("035", "860078828", "11", "EPS SANITAS (alt)"), - ("036", "860078828", "11", "EPS SANITAS (alt)"), - ("20062026", "800182856", "01", "SUBSIDIADO"), - ("CW225489", "899999068", "07", "POLIZA / SEGURO"), + ("001", "860078828", "11", "EPS SANITAS", 0), + ("002", "830054904", "11", "EPS COMPENSAR", 0), + ("003", "900278729", "12", "PARTICULAR", 0), + ("004", "800106339", "11", "EPS NUEVA EPS", 0), + ("005", "800153424", "11", "EPS SURA", 0), + ("006", "805009741", "11", "EPS COOMEVA", 0), + ("007", "860002183", "11", "EPS FAMISANAR", 0), + ("008", "860002503", "11", "EPS CRUZ BLANCA", 0), + ("009", "860027404", "11", "EPS COLSANITAS", 0), + ("010", "860039988", "11", "EPS SALUD TOTAL", 0), + ("011", "890903790", "11", "EPS SAVIA SALUD", 0), + ("012", "900178724", "11", "EPS MUTUAL SER", 0), + ("034", "860078828", "11", "EPS SANITAS (alt)", 0), + ("035", "860078828", "11", "EPS SANITAS (alt)", 0), + ("036", "860078828", "11", "EPS SANITAS (alt)", 0), + ("20062026", "800182856", "01", "SUBSIDIADO", 0), + ("CW225489", "899999068", "07", "POLIZA / SEGURO", 0), + # Contratos excluidos del envío TNS + ("013", "", "11", "MEDILAVORO S.A.S", 1), + ("014", "", "11", "LABORATORIO UROCLINICO",1), + ("015", "", "11", "ANDRES AFANADOR VILLAMIZAR", 1), + ("016", "", "11", "OMAR FERNANDO RIBERO GOMEZ", 1), + ("017", "", "11", "CLAUDIA BELEN JULIO SEPULVEDA", 1), + ("018", "", "11", "LABORATORIO MICROBIOLOGICO - MARGIE OJEDA", 1), + ("019", "", "11", "LABORATORIO TOXICOLOGICO - MARTHA MORALES", 1), + ("020", "", "11", "MARTHA LUCIA GALLARDO", 1), + ("021", "", "11", "LABORATORIO VILMA OROZCO AYALA", 1), + ("022", "", "11", "CLINICA SAN JOSE DE CUCUTA", 1), + ("023", "", "11", "URONORTE S.A", 1), + ("024", "", "11", "LABORATORIO CLINICO BIOLAB S.A.S", 1), + ("025", "", "11", "JOEL LEONARDO CARRILLO CORREDOR", 1), + ("026", "", "11", "ROLANDO IVAN PENARANDA DEVIA", 1), + ("027", "", "11", "JOSE WILMER GARCIA CALDERON", 1), + ("028", "", "11", "ONCOMEDICAL IPS S.A.S", 1), + ("029", "", "11", "GENETIX S.A.S", 1), + ("030", "", "11", "NORFETUS S.A.S", 1), + ("031", "", "11", "TBTB GLOBAL LAB S.A.S", 1), + ("032", "", "11", "COLGENES S.A.S", 1), + ("033", "", "11", "IPS FIGURAS SPA CUCUTA S.A.S", 1), + ("037", "", "11", "CLINICA URGENCIAS LA MERCED", 1), + ("038", "", "11", "CLINICA COLSANITAS S.A.", 1), + ("039", "", "11", "GOMEZ GIL JOSE JESUS", 1), + ("040", "", "11", "MARTHA LILIANA SALGAR GALLEGO", 1), + ("041", "", "11", "GENCELL PHARMA S.A.S", 1), + ("042", "", "07", "AXA COLPATRIA HYC", 1), ] def ensure_defaults(): conn = get_connection() - for nc, nit, tu, desc in _SEED: + for nc, nit, tu, desc, excluir in _SEED: exists = conn.execute( "SELECT id FROM contratos WHERE numero_contrato = ?", (nc,) ).fetchone() if not exists: conn.execute( - "INSERT INTO contratos (numero_contrato, nit_empresa, tipo_usuario, descripcion) VALUES (?,?,?,?)", - (nc, nit, tu, desc), + "INSERT INTO contratos (numero_contrato, nit_empresa, tipo_usuario, descripcion, excluir) VALUES (?,?,?,?,?)", + (nc, nit, tu, desc, excluir), ) conn.commit() conn.close() @@ -57,6 +86,21 @@ def load_contrato_map() -> dict: return result +def load_excluded_set() -> set: + """Devuelve set de numero_contrato (raw + sin ceros) marcados como excluir=1.""" + conn = get_connection() + rows = conn.execute("SELECT numero_contrato FROM contratos WHERE excluir=1").fetchall() + conn.close() + result = set() + for r in rows: + nc = r["numero_contrato"].strip() + result.add(nc) + nc_s = nc.lstrip("0") or nc + if nc_s != nc: + result.add(nc_s) + return result + + @router.get("") async def contratos_page(request: Request, user: dict = Depends(get_current_user)): conn = get_connection() @@ -75,12 +119,13 @@ async def contrato_create( nit_empresa: str = Form(""), tipo_usuario: str = Form(...), descripcion: str = Form(""), + excluir: str = Form("0"), ): conn = get_connection() try: conn.execute( - "INSERT INTO contratos (numero_contrato, nit_empresa, tipo_usuario, descripcion) VALUES (?,?,?,?)", - (numero_contrato.strip(), nit_empresa.strip(), tipo_usuario.strip(), descripcion.strip()), + "INSERT INTO contratos (numero_contrato, nit_empresa, tipo_usuario, descripcion, excluir) VALUES (?,?,?,?,?)", + (numero_contrato.strip(), nit_empresa.strip(), tipo_usuario.strip(), descripcion.strip(), int(excluir)), ) conn.commit() except Exception: @@ -97,11 +142,24 @@ async def contrato_update( nit_empresa: str = Form(""), tipo_usuario: str = Form(...), descripcion: str = Form(""), + excluir: str = Form("0"), ): conn = get_connection() conn.execute( - "UPDATE contratos SET numero_contrato=?, nit_empresa=?, tipo_usuario=?, descripcion=? WHERE id=?", - (numero_contrato.strip(), nit_empresa.strip(), tipo_usuario.strip(), descripcion.strip(), contrato_id), + "UPDATE contratos SET numero_contrato=?, nit_empresa=?, tipo_usuario=?, descripcion=?, excluir=? WHERE id=?", + (numero_contrato.strip(), nit_empresa.strip(), tipo_usuario.strip(), descripcion.strip(), int(excluir), contrato_id), + ) + conn.commit() + conn.close() + return RedirectResponse("/contratos", status_code=302) + + +@router.post("/toggle-excluir/{contrato_id}") +async def toggle_excluir(contrato_id: int, user: dict = Depends(get_current_user)): + conn = get_connection() + conn.execute( + "UPDATE contratos SET excluir = CASE WHEN excluir=1 THEN 0 ELSE 1 END WHERE id=?", + (contrato_id,) ) conn.commit() conn.close() diff --git a/app/routes/transaccion.py b/app/routes/transaccion.py index f109552..7bef9d2 100644 --- a/app/routes/transaccion.py +++ b/app/routes/transaccion.py @@ -8,7 +8,7 @@ from app.auth import get_current_user from app.services.firebird_service import get_firebird_from_config from app.services.json_generator import generar_rda_paciente, agrupar_por_recepcion from app.services.api_client import get_tns_token, TNS_BASE -from app.routes.contratos import load_contrato_map +from app.routes.contratos import load_contrato_map, load_excluded_set router = APIRouter(prefix="/transaccion", tags=["transaccion"]) @@ -98,10 +98,13 @@ async def preview_transaccion( remis_def = cfg.get("remisionante_default", "00") prefijo_def = cfg.get("prefijo_tns_default", "00") contrato_map = load_contrato_map() + excluded = load_excluded_set() items = [] for id_rec, grupo_rows in grupos.items(): enviado = _is_sent(id_rec) + cod_c = str(grupo_rows[0].get("CODCONTRATO") or "").strip() + is_excluded = cod_c in excluded rda = generar_rda_paciente(grupo_rows, prof_def, esp_def, remis_def, prefijo_def, contrato_map=contrato_map) items.append({ "idrecepcion": id_rec, @@ -111,12 +114,14 @@ async def preview_transaccion( "examenes": [r.get("COD_EXAMEN", "") for r in grupo_rows], "valor": float(grupo_rows[0].get("VALORTOTAL") or 0), "enviado": enviado, + "excluido": is_excluded, "json": rda, }) - pendientes = sum(1 for i in items if not i["enviado"]) + pendientes = sum(1 for i in items if not i["enviado"] and not i["excluido"]) enviados_ok = sum(1 for i in items if i["enviado"] and i["enviado"]["status"] == "success") enviados_err = sum(1 for i in items if i["enviado"] and i["enviado"]["status"] == "error") + excluidos = sum(1 for i in items if i["excluido"]) return JSONResponse({ "success": True, @@ -124,6 +129,7 @@ async def preview_transaccion( "pendientes": pendientes, "enviados_ok": enviados_ok, "enviados_err": enviados_err, + "excluidos": excluidos, "items": items, }) @@ -149,6 +155,10 @@ async def send_one( if not grupo_rows: return JSONResponse({"success": False, "message": f"IDRECEPCION {idrecepcion} no encontrado"}) + cod_c = str(grupo_rows[0].get("CODCONTRATO") or "").strip() + if cod_c in load_excluded_set(): + return JSONResponse({"success": False, "message": f"Contrato {cod_c} está excluido del envío TNS"}) + token, token_err = await get_tns_token( cfg.get("tns_empresa", ""), cfg.get("tns_usuario", ""), cfg.get("tns_password", "") ) @@ -237,6 +247,12 @@ async def send_transaccion( if solo_pendientes == "1": grupos = {k: v for k, v in grupos.items() if not _is_sent(k)} + excluded = load_excluded_set() + grupos_enviar = {k: v for k, v in grupos.items() + if str(v[0].get("CODCONTRATO") or "").strip() not in excluded} + excluidos_count = len(grupos) - len(grupos_enviar) + grupos = grupos_enviar + contrato_map = load_contrato_map() token, token_err = await get_tns_token( @@ -306,6 +322,7 @@ async def send_transaccion( "success": err_count == 0, "total_enviados": ok_count, "total_errores": err_count, + "total_excluidos": excluidos_count, "resultados": resultados, }) @@ -340,6 +357,12 @@ async def send_direct( if not grupos: return JSONResponse({"success": False, "message": "Sin datos agrupables"}) + # Rechazar si todos los grupos pertenecen a contratos excluidos + excluded = load_excluded_set() + primer_contrato = str(list(grupos.values())[0][0].get("CODCONTRATO") or "").strip() + if primer_contrato in excluded: + return JSONResponse({"success": False, "message": f"Contrato {primer_contrato} está excluido del envío TNS"}) + token, token_err = await get_tns_token( cfg.get("tns_empresa", ""), cfg.get("tns_usuario", ""), cfg.get("tns_password", "") ) diff --git a/app/templates/contratos.html b/app/templates/contratos.html index 00e2948..153dec0 100644 --- a/app/templates/contratos.html +++ b/app/templates/contratos.html @@ -2,7 +2,7 @@ {% block title %}Contratos{% endblock %} {% block header %}Contratos{% endblock %} {% block content %} -
+
@@ -10,7 +10,7 @@

Agregar Contrato

-
+
-
+
+ + {% else %} + + {% endif %} + + + + @@ -100,7 +118,7 @@ {% else %} - No hay contratos registrados + No hay contratos registrados {% endfor %} @@ -143,6 +161,10 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500">
+
+ + +