diff --git a/app/database.py b/app/database.py index a8ed9cf..2a6a024 100644 --- a/app/database.py +++ b/app/database.py @@ -53,6 +53,8 @@ def _migrate(conn): conn.execute("ALTER TABLE contratos ADD COLUMN excluir INTEGER NOT NULL DEFAULT 0") if "sin_contrato" not in contrato_cols: conn.execute("ALTER TABLE contratos ADD COLUMN sin_contrato INTEGER NOT NULL DEFAULT 0") + if "excluir_ventas" not in contrato_cols: + conn.execute("ALTER TABLE contratos ADD COLUMN excluir_ventas INTEGER NOT NULL DEFAULT 0") # Ampliar CHECK constraint de queries para incluir 'ventas' q_sql = conn.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='queries'").fetchone() if q_sql and "'ventas'" not in q_sql[0]: diff --git a/app/routes/contratos.py b/app/routes/contratos.py index e9c4e2a..ae3d3ed 100644 --- a/app/routes/contratos.py +++ b/app/routes/contratos.py @@ -6,71 +6,71 @@ from app.utils.activity import log_activity, get_ip router = APIRouter(prefix="/contratos", tags=["contratos"]) -# (numero_contrato, nit_empresa, tipo_usuario, descripcion, excluir, sin_contrato) +# (numero_contrato, nit_empresa, tipo_usuario, descripcion, excluir_rda, sin_contrato, excluir_ventas) _SEED = [ - ("001", "860078828", "11", "EPS SANITAS", 0, 0), - ("002", "830054904", "11", "EPS COMPENSAR", 0, 0), - ("003", "900278729", "12", "PARTICULAR", 0, 0), - ("004", "800106339", "11", "EPS NUEVA EPS", 0, 0), - ("005", "800153424", "11", "EPS SURA", 0, 0), - ("006", "805009741", "11", "EPS COOMEVA", 0, 0), - ("007", "860002183", "11", "EPS FAMISANAR", 0, 0), - ("008", "860002503", "11", "EPS CRUZ BLANCA", 0, 0), - ("009", "860027404", "11", "EPS COLSANITAS", 0, 0), - ("010", "860039988", "11", "EPS SALUD TOTAL", 0, 0), - ("011", "890903790", "11", "EPS SAVIA SALUD", 0, 0), - ("012", "900178724", "11", "EPS MUTUAL SER", 0, 0), - ("034", "860078828", "11", "EPS SANITAS (alt)", 0, 0), - ("035", "860078828", "11", "EPS SANITAS (alt)", 0, 0), - ("036", "860078828", "11", "EPS SANITAS (alt)", 0, 0), - ("20062026", "800182856", "01", "SUBSIDIADO", 0, 0), - ("CW225489", "899999068", "07", "POLIZA / SEGURO", 0, 0), + ("001", "860078828", "11", "EPS SANITAS", 0, 0, 0), + ("002", "830054904", "11", "EPS COMPENSAR", 0, 0, 0), + ("003", "900278729", "12", "PARTICULAR", 0, 0, 0), + ("004", "800106339", "11", "EPS NUEVA EPS", 0, 0, 0), + ("005", "800153424", "11", "EPS SURA", 0, 0, 0), + ("006", "805009741", "11", "EPS COOMEVA", 0, 0, 0), + ("007", "860002183", "11", "EPS FAMISANAR", 0, 0, 0), + ("008", "860002503", "11", "EPS CRUZ BLANCA", 0, 0, 0), + ("009", "860027404", "11", "EPS COLSANITAS", 0, 0, 0), + ("010", "860039988", "11", "EPS SALUD TOTAL", 0, 0, 0), + ("011", "890903790", "11", "EPS SAVIA SALUD", 0, 0, 0), + ("012", "900178724", "11", "EPS MUTUAL SER", 0, 0, 0), + ("034", "860078828", "11", "EPS SANITAS (alt)", 0, 0, 0), + ("035", "860078828", "11", "EPS SANITAS (alt)", 0, 0, 0), + ("036", "860078828", "11", "EPS SANITAS (alt)", 0, 0, 0), + ("20062026", "800182856", "01", "SUBSIDIADO", 0, 0, 0), + ("CW225489", "899999068", "07", "POLIZA / SEGURO", 0, 0, 0), # Contratos excluidos del envío TNS - ("013", "", "11", "MEDILAVORO S.A.S", 0, 0), - ("014", "", "11", "LABORATORIO UROCLINICO",0, 0), - ("015", "", "11", "ANDRES AFANADOR VILLAMIZAR", 1, 0), - ("016", "", "11", "OMAR FERNANDO RIBERO GOMEZ", 1, 0), - ("017", "", "11", "CLAUDIA BELEN JULIO SEPULVEDA", 1, 0), - ("018", "", "11", "LABORATORIO MICROBIOLOGICO - MARGIE OJEDA", 1, 0), - ("019", "", "11", "LABORATORIO TOXICOLOGICO - MARTHA MORALES", 1, 0), - ("020", "", "11", "MARTHA LUCIA GALLARDO", 1, 0), - ("021", "", "11", "LABORATORIO VILMA OROZCO AYALA", 1, 0), - ("022", "", "11", "CLINICA SAN JOSE DE CUCUTA", 1, 0), - ("023", "", "11", "URONORTE S.A", 1, 0), - ("024", "", "11", "LABORATORIO CLINICO BIOLAB S.A.S", 1, 0), - ("025", "", "11", "JOEL LEONARDO CARRILLO CORREDOR", 1, 0), - ("026", "", "11", "ROLANDO IVAN PENARANDA DEVIA", 1, 0), - ("027", "", "11", "JOSE WILMER GARCIA CALDERON", 1, 0), - ("028", "", "11", "ONCOMEDICAL IPS S.A.S", 1, 0), - ("029", "", "11", "GENETIX S.A.S", 1, 0), - ("030", "", "11", "NORFETUS S.A.S", 1, 0), - ("031", "", "11", "TBTB GLOBAL LAB S.A.S", 1, 0), - ("032", "", "11", "COLGENES S.A.S", 1, 0), - ("033", "", "11", "IPS FIGURAS SPA CUCUTA S.A.S", 1, 0), - ("037", "", "11", "CLINICA URGENCIAS LA MERCED", 1, 0), - ("038", "", "11", "CLINICA COLSANITAS S.A.", 1, 0), - ("039", "", "11", "GOMEZ GIL JOSE JESUS", 1, 0), - ("040", "", "11", "MARTHA LILIANA SALGAR GALLEGO", 0, 1), - ("041", "", "11", "GENCELL PHARMA S.A.S", 1, 0), - ("042", "", "07", "AXA COLPATRIA HYC", 1, 0), + ("013", "", "11", "MEDILAVORO S.A.S", 0, 0, 0), + ("014", "", "11", "LABORATORIO UROCLINICO",0, 0, 0), + ("015", "", "11", "ANDRES AFANADOR VILLAMIZAR", 1, 0, 0), + ("016", "", "11", "OMAR FERNANDO RIBERO GOMEZ", 1, 0, 0), + ("017", "", "11", "CLAUDIA BELEN JULIO SEPULVEDA", 1, 0, 0), + ("018", "", "11", "LABORATORIO MICROBIOLOGICO - MARGIE OJEDA", 1, 0, 0), + ("019", "", "11", "LABORATORIO TOXICOLOGICO - MARTHA MORALES", 1, 0, 0), + ("020", "", "11", "MARTHA LUCIA GALLARDO", 1, 0, 0), + ("021", "", "11", "LABORATORIO VILMA OROZCO AYALA", 1, 0, 0), + ("022", "", "11", "CLINICA SAN JOSE DE CUCUTA", 1, 0, 0), + ("023", "", "11", "URONORTE S.A", 1, 0, 0), + ("024", "", "11", "LABORATORIO CLINICO BIOLAB S.A.S", 1, 0, 0), + ("025", "", "11", "JOEL LEONARDO CARRILLO CORREDOR", 1, 0, 0), + ("026", "", "11", "ROLANDO IVAN PENARANDA DEVIA", 1, 0, 0), + ("027", "", "11", "JOSE WILMER GARCIA CALDERON", 1, 0, 0), + ("028", "", "11", "ONCOMEDICAL IPS S.A.S", 1, 0, 0), + ("029", "", "11", "GENETIX S.A.S", 1, 0, 0), + ("030", "", "11", "NORFETUS S.A.S", 1, 0, 0), + ("031", "", "11", "TBTB GLOBAL LAB S.A.S", 1, 0, 0), + ("032", "", "11", "COLGENES S.A.S", 1, 0, 0), + ("033", "", "11", "IPS FIGURAS SPA CUCUTA S.A.S", 1, 0, 0), + ("037", "", "11", "CLINICA URGENCIAS LA MERCED", 1, 0, 0), + ("038", "", "11", "CLINICA COLSANITAS S.A.", 1, 0, 0), + ("039", "", "11", "GOMEZ GIL JOSE JESUS", 1, 0, 0), + ("040", "", "11", "MARTHA LILIANA SALGAR GALLEGO", 1, 1, 0), + ("041", "", "11", "GENCELL PHARMA S.A.S", 1, 0, 0), + ("042", "", "07", "AXA COLPATRIA HYC", 1, 0, 0), ] def ensure_defaults(): conn = get_connection() - for nc, nit, tu, desc, excluir, sin_contrato in _SEED: + for nc, nit, tu, desc, excluir, sin_contrato, excluir_ventas 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, excluir, sin_contrato) VALUES (?,?,?,?,?,?)", - (nc, nit, tu, desc, excluir, sin_contrato), + "INSERT INTO contratos (numero_contrato, nit_empresa, tipo_usuario, descripcion, excluir, sin_contrato, excluir_ventas) VALUES (?,?,?,?,?,?,?)", + (nc, nit, tu, desc, excluir, sin_contrato, excluir_ventas), ) else: conn.execute( - "UPDATE contratos SET excluir=?, sin_contrato=? WHERE numero_contrato=?", - (excluir, sin_contrato, nc), + "UPDATE contratos SET excluir=?, sin_contrato=?, excluir_ventas=? WHERE numero_contrato=?", + (excluir, sin_contrato, excluir_ventas, nc), ) conn.commit() conn.close() @@ -108,7 +108,7 @@ def load_sin_contrato_set() -> set: def load_excluded_set() -> set: - """Devuelve set de numero_contrato (raw + sin ceros) marcados como excluir=1.""" + """Devuelve set de numero_contrato marcados como excluir=1 (bloqueados para RDA).""" conn = get_connection() rows = conn.execute("SELECT numero_contrato FROM contratos WHERE excluir=1").fetchall() conn.close() @@ -122,6 +122,21 @@ def load_excluded_set() -> set: return result +def load_excluded_ventas_set() -> set: + """Devuelve set de numero_contrato marcados como excluir_ventas=1 (bloqueados para Ventas).""" + conn = get_connection() + rows = conn.execute("SELECT numero_contrato FROM contratos WHERE excluir_ventas=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() @@ -142,12 +157,13 @@ async def contrato_create( descripcion: str = Form(""), excluir: str = Form("0"), sin_contrato: str = Form("0"), + excluir_ventas: str = Form("0"), ): conn = get_connection() try: conn.execute( - "INSERT INTO contratos (numero_contrato, nit_empresa, tipo_usuario, descripcion, excluir, sin_contrato) VALUES (?,?,?,?,?,?)", - (numero_contrato.strip(), nit_empresa.strip(), tipo_usuario.strip(), descripcion.strip(), int(excluir), int(sin_contrato)), + "INSERT INTO contratos (numero_contrato, nit_empresa, tipo_usuario, descripcion, excluir, sin_contrato, excluir_ventas) VALUES (?,?,?,?,?,?,?)", + (numero_contrato.strip(), nit_empresa.strip(), tipo_usuario.strip(), descripcion.strip(), int(excluir), int(sin_contrato), int(excluir_ventas)), ) conn.commit() log_activity(user["user_id"], user["username"], "contrato_creado", @@ -169,11 +185,12 @@ async def contrato_update( descripcion: str = Form(""), excluir: str = Form("0"), sin_contrato: str = Form("0"), + excluir_ventas: str = Form("0"), ): conn = get_connection() conn.execute( - "UPDATE contratos SET numero_contrato=?, nit_empresa=?, tipo_usuario=?, descripcion=?, excluir=?, sin_contrato=? WHERE id=?", - (numero_contrato.strip(), nit_empresa.strip(), tipo_usuario.strip(), descripcion.strip(), int(excluir), int(sin_contrato), contrato_id), + "UPDATE contratos SET numero_contrato=?, nit_empresa=?, tipo_usuario=?, descripcion=?, excluir=?, sin_contrato=?, excluir_ventas=? WHERE id=?", + (numero_contrato.strip(), nit_empresa.strip(), tipo_usuario.strip(), descripcion.strip(), int(excluir), int(sin_contrato), int(excluir_ventas), contrato_id), ) conn.commit() log_activity(user["user_id"], user["username"], "contrato_editado", @@ -215,6 +232,22 @@ async def toggle_sin_contrato(contrato_id: int, request: Request, user: dict = D return RedirectResponse("/contratos", status_code=302) +@router.post("/toggle-excluir-ventas/{contrato_id}") +async def toggle_excluir_ventas(contrato_id: int, request: Request, user: dict = Depends(get_current_user)): + conn = get_connection() + conn.execute( + "UPDATE contratos SET excluir_ventas = CASE WHEN excluir_ventas=1 THEN 0 ELSE 1 END WHERE id=?", + (contrato_id,) + ) + conn.commit() + row = conn.execute("SELECT numero_contrato, excluir_ventas FROM contratos WHERE id=?", (contrato_id,)).fetchone() + if row: + log_activity(user["user_id"], user["username"], "contrato_toggle_ventas", + f"Contrato {row['numero_contrato']} excluir_ventas→{row['excluir_ventas']}", get_ip(request)) + conn.close() + return RedirectResponse("/contratos", status_code=302) + + @router.post("/delete/{contrato_id}") async def contrato_delete(contrato_id: int, user: dict = Depends(get_current_user)): conn = get_connection() diff --git a/app/routes/ventas.py b/app/routes/ventas.py index a780882..a5aece8 100644 --- a/app/routes/ventas.py +++ b/app/routes/ventas.py @@ -9,6 +9,7 @@ from app.services.firebird_service import get_firebird_from_config from app.services.json_generator import generar_factura_venta from app.services.api_client import get_tns_token, TNS_BASE from app.utils.activity import log_activity, get_ip +from app.routes.contratos import load_excluded_ventas_set router = APIRouter(prefix="/ventas", tags=["ventas"]) @@ -141,7 +142,11 @@ async def preview_ventas( if not rows: return JSONResponse({"success": False, "message": "Sin datos"}) - grupos = _agrupar(rows) + excluded_ventas = load_excluded_ventas_set() + grupos_all = _agrupar(rows) + grupos = {k: v for k, v in grupos_all.items() + if str(v[0].get("CODCONTRATO") or "").strip() not in excluded_ventas} + items = [] for key, grupo_rows in grupos.items(): enviado = _is_sent(key) @@ -245,7 +250,10 @@ async def send_ventas( if not rows: return JSONResponse({"success": False, "message": "Sin datos"}) - grupos = _agrupar(rows) + excluded_ventas = load_excluded_ventas_set() + grupos_all = _agrupar(rows) + grupos = {k: v for k, v in grupos_all.items() + if str(v[0].get("CODCONTRATO") or "").strip() not in excluded_ventas} if solo_pendientes == "1": grupos = {k: v for k, v in grupos.items() if not _is_sent(k)} diff --git a/app/templates/contratos.html b/app/templates/contratos.html index 8cebbb7..e1b88f0 100644 --- a/app/templates/contratos.html +++ b/app/templates/contratos.html @@ -67,7 +67,8 @@ NIT Empresa Tipo Usuario Descripción - Envío TNS + Excluir RDA + Excluir Ventas Sin Contrato Acciones @@ -105,6 +106,19 @@ {% endif %} + +
+ {% if c.excluir_ventas %} + + {% else %} + + {% endif %} +
+
{% if c.sin_contrato %} @@ -119,7 +133,7 @@
- @@ -175,14 +189,18 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500"> -
+
+
@@ -200,7 +218,7 @@