From e044f21e3e01286d1cb50e53719d03f675d8eeb3 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:33:46 -0500 Subject: [PATCH] feat: store and display per-patient sync detail in historial - Add detalle_json column to sync_wa_log via migration - guardar_sync_log() now stores doc, nombre, action, examenes count per patient - Historial table shows "Ver N" button that expands a row with patient list, action badge (Nuevo/Actualizado/Omitido) and exam count per patient Co-Authored-By: Claude Sonnet 4.6 --- app/database.py | 4 +++ app/services/whatsapp_sync.py | 21 ++++++++++++--- app/templates/envios_erp.html | 51 +++++++++++++++++++++++++++-------- 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/app/database.py b/app/database.py index 2a6a024..a204a42 100644 --- a/app/database.py +++ b/app/database.py @@ -14,6 +14,10 @@ def get_connection(): def _migrate(conn): + sync_cols = {r[1] for r in conn.execute("PRAGMA table_info(sync_wa_log)")} + if "detalle_json" not in sync_cols: + conn.execute("ALTER TABLE sync_wa_log ADD COLUMN detalle_json TEXT") + cols = {r[1] for r in conn.execute("PRAGMA table_info(envios)")} if "idrecepcion" not in cols: conn.execute("ALTER TABLE envios ADD COLUMN idrecepcion INTEGER") diff --git a/app/services/whatsapp_sync.py b/app/services/whatsapp_sync.py index 605eee1..8ea172f 100644 --- a/app/services/whatsapp_sync.py +++ b/app/services/whatsapp_sync.py @@ -14,22 +14,34 @@ from app.database import get_connection def guardar_sync_log( resultado: dict, - user_id: int, + user_id, origen: str = "manual", modo: str = "insertar", ) -> None: + detalle_raw = resultado.get("detalle", []) + errores_det = None - errores = [d for d in resultado.get("detalle", []) if not d.get("ok")] + errores = [d for d in detalle_raw if not d.get("ok")] if errores: errores_det = json.dumps( [{"doc": e["doc"], "nombre": e["nombre"], "msg": e["message"]} for e in errores], ensure_ascii=False, ) + + detalle_json = None + if detalle_raw: + detalle_json = json.dumps( + [{"doc": d["doc"], "nombre": d["nombre"], "action": d.get("action", ""), + "examenes": d.get("examenes_guardados", 0)} + for d in detalle_raw], + ensure_ascii=False, + ) + conn = get_connection() conn.execute( """INSERT INTO sync_wa_log - (user_id, origen, modo, total, created, skipped, updated, errores, errores_det) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", + (user_id, origen, modo, total, created, skipped, updated, errores, errores_det, detalle_json) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", ( user_id, origen, @@ -40,6 +52,7 @@ def guardar_sync_log( resultado.get("updated", 0), resultado.get("errores", 0), errores_det, + detalle_json, ), ) conn.commit() diff --git a/app/templates/envios_erp.html b/app/templates/envios_erp.html index 040c72a..2d8175d 100644 --- a/app/templates/envios_erp.html +++ b/app/templates/envios_erp.html @@ -158,6 +158,11 @@ function switchTab(name) { const _origenLabel = { manual: 'Manual', tercero: 'Tercero', scheduler: 'Scheduler', automation: 'Automatización' }; const _modoLabel = { insertar: 'Solo nuevos', upsert: 'Upsert' }; +function toggleDet(id) { + const row = document.getElementById(id); + if (row) row.classList.toggle('hidden'); +} + async function ejecutarSyncNow() { const btn = document.getElementById('btn-sync-now'); const ventana = document.getElementById('sel-ventana').value; @@ -235,34 +240,58 @@ async function cargarHistorialScheduler() { Fecha + Usuario Procesados Nuevos - Omitidos Actualizados Errores + Detalle - ${sched.map(r => { + ${sched.map((r, i) => { const fecha = r.created_at.replace('T', ' ').slice(0, 16); const errDet = r.errores_det ? JSON.parse(r.errores_det) : []; + const pacientes = r.detalle_json ? JSON.parse(r.detalle_json) : []; + const rowId = 'hist-det-' + i; return ` ${fecha} + ${r.username || '—'} ${r.total} ${r.created} - ${r.skipped} ${r.updated} - ${r.errores > 0 && errDet.length ? ` -
- ${r.errores} -
- ${errDet.map(e => `
${e.doc} — ${e.msg}
`).join('')} -
-
` : r.errores || '—'} + ${r.errores > 0 && errDet.length + ? errDet.map(e => `
${e.doc} — ${e.msg}
`).join('') + : r.errores || '—'} - `; + + ${pacientes.length ? ` + ` : '—'} + + + ${pacientes.length ? ` + + +
+ ${pacientes.map(p => { + const badge = p.action === 'created' ? 'Nuevo' + : p.action === 'updated' ? 'Actualizado' + : p.action === 'skipped' ? 'Omitido' + : `${p.action}`; + const exBadge = p.examenes > 0 + ? `${p.examenes} exám.` : ''; + return `
+ ${p.doc} + ${p.nombre} + ${badge} ${exBadge} +
`; + }).join('')} +
+ + ` : ''}`; }).join('')}