feat: excluir contratos del envío TNS

- Columna excluir en tabla contratos (migración automática)
- 25 contratos nuevos sembrados con excluir=1 (laboratorios externos, clínicas, médicos particulares)
- load_excluded_set() en contratos.py para consultar el set en runtime
- preview: marca items excluidos y los reporta en el conteo
- send/send-one/send-direct: bloquea envío si contrato está excluido
- automation preview+run: filtra excluidos antes del loop, reporta count
- UI /contratos: columna Envío TNS con toggle Activo/Excluido, fila en rojo si excluida

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-10 15:44:26 -05:00
co-authored by Claude Sonnet 4.6
parent 3baa6e5f75
commit 200a3f550b
5 changed files with 156 additions and 37 deletions
+82 -24
View File
@@ -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()