From 1aab14f705c9ad2c934df30bdfeb298a81444046 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Thu, 9 Jul 2026 11:06:14 -0500 Subject: [PATCH] =?UTF-8?q?feat(pacientes):=20modo=20insertar=20en=20sync-?= =?UTF-8?q?all=20=E2=80=94=20solo=20crea=20nuevos,=20omite=20existentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sync_todos() ahora acepta modo='insertar'|'upsert'. La ruta /pacientes/sync-all usa insertar: skippea cédulas que ya están en lab_pacientes. Los hooks automáticos (terceros/automation) siguen en upsert. Co-Authored-By: Claude Sonnet 4.6 --- app/routes/pacientes.py | 8 ++++---- app/services/whatsapp_sync.py | 23 ++++++++++++++++------- app/templates/pacientes.html | 10 +++++++--- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/app/routes/pacientes.py b/app/routes/pacientes.py index 9cf4a0c..6340f57 100644 --- a/app/routes/pacientes.py +++ b/app/routes/pacientes.py @@ -117,12 +117,12 @@ async def sync_all( return JSONResponse({"success": False, "message": "No se encontraron pacientes con esos criterios."}) timeout = int(configs.get("api_timeout", 30)) - resultado = await sync_todos(rows, ingest_url, wa_key, timeout) + resultado = await sync_todos(rows, ingest_url, wa_key, timeout, modo="insertar") resultado["success"] = True resultado["message"] = ( - f"{resultado['total']} pacientes procesados — " - f"{resultado['created']} creados, " - f"{resultado['updated']} actualizados, " + f"{resultado['total']} procesados — " + f"{resultado['created']} nuevos, " + f"{resultado['skipped']} ya existían, " f"{resultado['errores']} errores." ) return JSONResponse(resultado) diff --git a/app/services/whatsapp_sync.py b/app/services/whatsapp_sync.py index 156a81b..7853032 100644 --- a/app/services/whatsapp_sync.py +++ b/app/services/whatsapp_sync.py @@ -63,9 +63,16 @@ def mapear_paciente(row: dict) -> dict: } -async def sync_paciente(row: dict, url: str, api_key: str, client: Optional[httpx.AsyncClient] = None) -> dict: +async def sync_paciente( + row: dict, + url: str, + api_key: str, + client: Optional[httpx.AsyncClient] = None, + modo: str = "upsert", +) -> dict: """Envía un paciente al endpoint de WhatsApp. Retorna {ok, action, message}.""" payload = mapear_paciente(row) + payload["modo"] = modo headers = { "Content-Type": "application/json", "X-Lab-Key": api_key, @@ -95,17 +102,19 @@ async def sync_paciente(row: dict, url: str, api_key: str, client: Optional[http } -async def sync_todos(rows: list, url: str, api_key: str, timeout: int = 30) -> dict: - """Envía una lista de filas de pacientes. Retorna resumen {total, created, updated, errores}.""" - resultado = {"total": len(rows), "created": 0, "updated": 0, "errores": 0, "detalle": []} - headers = {"Content-Type": "application/json", "X-Lab-Key": api_key} +async def sync_todos(rows: list, url: str, api_key: str, timeout: int = 30, modo: str = "upsert") -> dict: + """Envía una lista de filas de pacientes. Retorna resumen {total, created, skipped, updated, errores}.""" + resultado = {"total": len(rows), "created": 0, "skipped": 0, "updated": 0, "errores": 0, "detalle": []} async with httpx.AsyncClient(timeout=timeout) as client: for row in rows: - r = await sync_paciente(row, url, api_key, client) + r = await sync_paciente(row, url, api_key, client, modo) if r["ok"]: - if r["action"] == "created": + action = r["action"] + if action == "created": resultado["created"] += 1 + elif action == "skipped": + resultado["skipped"] += 1 else: resultado["updated"] += 1 else: diff --git a/app/templates/pacientes.html b/app/templates/pacientes.html index 4504f5f..c3e26f6 100644 --- a/app/templates/pacientes.html +++ b/app/templates/pacientes.html @@ -135,7 +135,7 @@ async function runSync() { result.innerHTML = `

${json.message}

-
+

${json.total}

Total

@@ -145,8 +145,12 @@ async function runSync() {

Nuevos

-

${json.updated}

-

Actualizados

+

${json.skipped ?? 0}

+

Ya existían

+
+
+

${json.errores}

+

Errores

${json.errores > 0 ? `

${json.errores} errores — revisa los detalles abajo.

` : ''}