feat: paso 3 pre-servicios RCXC/SC y limpieza de código copago
- Agrega paso 3 en automatización: envía RDA desde PRESSERV_DIAN (prefijos RCXC/SC) para pacientes EPS con PS_NUM IS NOT NULL - Filtra paso 2 con PS_NUM IS NULL para separar particulares/empresas de EPS - Elimina parámetro copago y función _calcular_descuento_pct (código muerto) - Limpia referencia a d.copago en automation.html (UI paso 3) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
c20e1a7476
commit
c2a092c0e7
+119
-4
@@ -42,6 +42,7 @@ LEFT JOIN EMPRESA e ON e.NIT = r.NIT_EMPRESA
|
||||
LEFT JOIN CIUDAD c ON c.CODIGO = p.CIUDAD
|
||||
WHERE r.FECHA_RECEPCION BETWEEN :fecha_ini AND :fecha_fin
|
||||
AND r.NUM_FACTURA > 0
|
||||
AND r.PS_NUM IS NULL
|
||||
{filtro_contrato_pac}
|
||||
"""
|
||||
|
||||
@@ -79,11 +80,63 @@ 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.FECHA_RECEPCION BETWEEN :fecha_ini AND :fecha_fin
|
||||
AND r.NUM_FACTURA > 0
|
||||
AND r.PS_NUM IS NULL
|
||||
{filtro_contrato_rda}
|
||||
ORDER BY r.IDRECEPCION
|
||||
"""
|
||||
|
||||
|
||||
_SQL_PRESERV = """
|
||||
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 r.FECHA_RECEPCION BETWEEN :fecha_ini AND :fecha_fin
|
||||
AND (ps.PS_ANULADA IS NULL OR ps.PS_ANULADA = 'F')
|
||||
ORDER BY ps.ID_PS, rel.COD_EXAMEN
|
||||
"""
|
||||
|
||||
|
||||
def _agrupar_por_presserv(rows: list) -> dict:
|
||||
"""Agrupa filas de pre-servicios por ID_PS."""
|
||||
from collections import defaultdict
|
||||
grupos = defaultdict(list)
|
||||
for row in rows:
|
||||
grupos[row.get("ID_PS")].append(dict(row))
|
||||
return grupos
|
||||
|
||||
|
||||
@router.get("")
|
||||
async def automation_page(request: Request, user: dict = Depends(get_current_user)):
|
||||
today = date.today().isoformat()
|
||||
@@ -134,17 +187,27 @@ async def preview_automation(
|
||||
return JSONResponse({"success": False, "message": f"Error BD pacientes: {err1}"})
|
||||
|
||||
ok2, err2, rows_rda = fb.execute_query(sql_rda, params)
|
||||
fb.disconnect()
|
||||
if not ok2:
|
||||
fb.disconnect()
|
||||
return JSONResponse({"success": False, "message": f"Error BD RDA: {err2}"})
|
||||
|
||||
grupos_all = agrupar_por_recepcion(rows_rda)
|
||||
ok3, err3, rows_ps = fb.execute_query(_SQL_PRESERV, {"fecha_ini": fecha_ini, "fecha_fin": fecha_fin})
|
||||
fb.disconnect()
|
||||
if not ok3:
|
||||
return JSONResponse({"success": False, "message": f"Error BD Pre-servicios: {err3}"})
|
||||
|
||||
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}
|
||||
excluidos_count = len(grupos_all) - len(grupos)
|
||||
total_examenes = sum(len(v) for v in grupos.values())
|
||||
|
||||
grupos_ps_all = _agrupar_por_presserv(rows_ps)
|
||||
grupos_ps = {k: v for k, v in grupos_ps_all.items()
|
||||
if str(v[0].get("CODCONTRATO") or "").strip() not in excluded}
|
||||
|
||||
# Agrupar RDA por COD_PACIENTE
|
||||
rda_por_pac = {}
|
||||
for id_rec, filas in grupos.items():
|
||||
@@ -180,6 +243,7 @@ async def preview_automation(
|
||||
"recepciones": len(grupos),
|
||||
"examenes": total_examenes,
|
||||
"excluidos": excluidos_count,
|
||||
"preservicios": len(grupos_ps),
|
||||
"pacientes_preview": pacientes_preview,
|
||||
})
|
||||
|
||||
@@ -215,10 +279,16 @@ async def run_automation(
|
||||
|
||||
# ── Paso 2: obtener recepciones ───────────────────────────────────────────
|
||||
ok2, err2, rows_rda = fb.execute_query(sql_rda, params)
|
||||
fb.disconnect()
|
||||
if not ok2:
|
||||
fb.disconnect()
|
||||
return JSONResponse({"success": False, "message": f"Error Firebird RDA: {err2}"})
|
||||
|
||||
# ── Paso 3: obtener pre-servicios ─────────────────────────────────────────
|
||||
ok3, err3, rows_ps = fb.execute_query(_SQL_PRESERV, {"fecha_ini": fecha_ini, "fecha_fin": fecha_fin})
|
||||
fb.disconnect()
|
||||
if not ok3:
|
||||
return JSONResponse({"success": False, "message": f"Error Firebird Pre-servicios: {err3}"})
|
||||
|
||||
if not rows_pac and not rows_rda:
|
||||
return JSONResponse({"success": False, "message": f"No hay datos para la fecha {fecha}"})
|
||||
|
||||
@@ -239,6 +309,7 @@ async def run_automation(
|
||||
"fecha": fecha,
|
||||
"paso1_terceros": {"enviados": 0, "errores": 0, "detalle": []},
|
||||
"paso2_rda": {"enviados": 0, "errores": 0, "detalle": []},
|
||||
"paso3_preserv": {"enviados": 0, "errores": 0, "detalle": []},
|
||||
}
|
||||
|
||||
# ── PASO 1: Enviar Terceros ───────────────────────────────────────────────
|
||||
@@ -324,10 +395,54 @@ async def run_automation(
|
||||
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)
|
||||
grupos_ps = {k: v for k, v in grupos_ps_all.items()
|
||||
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=ps_prefijo,
|
||||
)
|
||||
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
|
||||
|
||||
resultado["paso3_preserv"]["detalle"].append({
|
||||
"factura": factura_ps,
|
||||
"paciente": str(grupo_rows[0].get("COD_PACIENTE", "")),
|
||||
"examenes": len(grupo_rows),
|
||||
"ok": ok, "msg": msg,
|
||||
})
|
||||
|
||||
_guardar_envio(user["user_id"], "preserv", factura_ps, rda_json, msg, ok,
|
||||
fecha_inicio=fecha, fecha_fin=fecha,
|
||||
servicios=len(grupo_rows))
|
||||
|
||||
r1 = resultado["paso1_terceros"]
|
||||
r2 = resultado["paso2_rda"]
|
||||
r3 = resultado["paso3_preserv"]
|
||||
log_activity(user["user_id"], user["username"], "automation_run",
|
||||
f"Fecha {fecha} | Terceros: {r1['enviados']} OK/{r1['errores']} err | RDA: {r2['enviados']} OK/{r2['errores']} err/{r2.get('excluidos',0)} excluidos",
|
||||
f"Fecha {fecha} | Terceros: {r1['enviados']} OK/{r1['errores']} err | "
|
||||
f"RDA: {r2['enviados']} OK/{r2['errores']} err | "
|
||||
f"PreServ: {r3['enviados']} OK/{r3['errores']} err",
|
||||
get_ip(request))
|
||||
return JSONResponse({"success": True, "resultado": resultado})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user