Automation preview: show RDA per patient on click

Preview now returns all patients with their grouped receptions.
Clicking a patient row expands/collapses their RDA list showing
factura, fecha, exam count, diagnosis, and total value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-25 19:49:21 -05:00
co-authored by Claude Sonnet 4.6
parent 7dc8f37c36
commit dbaf49b30e
2 changed files with 55 additions and 12 deletions
+18 -2
View File
@@ -107,13 +107,30 @@ async def preview_automation(
grupos = agrupar_por_recepcion(rows_rda)
total_examenes = sum(len(v) for v in grupos.values())
# Agrupar RDA por COD_PACIENTE
rda_por_pac = {}
for id_rec, filas in grupos.items():
cod = str(filas[0].get("COD_PACIENTE", ""))
if cod not in rda_por_pac:
rda_por_pac[cod] = []
rda_por_pac[cod].append({
"id_recepcion": id_rec,
"factura": f"{str(filas[0].get('PREFIJO', '')).strip()}-{filas[0].get('NUM_FACTURA', '')}",
"fecha": str(filas[0].get("FECHA_RECEPCION", ""))[:10],
"examenes": len(filas),
"valor": float(filas[0].get("VALORTOTAL") or 0),
"diag": str(filas[0].get("DIAG_PPAL") or ""),
})
pacientes_preview = [
{
"codigo": str(p.get("CODIGO", "")),
"doc": str(p.get("DOCIDENT", "")),
"nombre": f"{p.get('NOMBRES', '')} {p.get('APELLIDOS', '')}".strip(),
"tipo": str(p.get("TIPOIDENT", "")),
"rda": rda_por_pac.get(str(p.get("CODIGO", "")), []),
}
for p in rows_pac[:10]
for p in rows_pac
]
return JSONResponse({
@@ -123,7 +140,6 @@ async def preview_automation(
"recepciones": len(grupos),
"examenes": total_examenes,
"pacientes_preview": pacientes_preview,
"hay_mas": len(rows_pac) > 10,
})
+37 -10
View File
@@ -58,8 +58,8 @@
</div>
</div>
<div>
<p class="text-xs font-medium text-gray-600 mb-2">Primeros pacientes:</p>
<div id="preview-table" class="divide-y divide-gray-100 border border-gray-100 rounded-lg overflow-hidden text-sm"></div>
<p class="text-xs font-medium text-gray-600 mb-2">Pacientes — haz clic para ver sus recepciones:</p>
<div id="preview-table" class="border border-gray-100 rounded-lg overflow-hidden text-sm"></div>
</div>
</div>
</div>
@@ -129,16 +129,35 @@ async function previewAutomation() {
table.innerHTML = '<div class="p-4 text-gray-400 text-center">No hay pacientes para esta fecha</div>';
showToast('No hay datos para esa fecha', 'warning');
} else {
table.innerHTML = data.pacientes_preview.map(p => `
<div class="flex items-center gap-3 px-4 py-2 text-sm hover:bg-gray-50">
<span class="text-gray-400 text-xs w-8">${p.tipo}</span>
<span class="text-gray-500 w-32 font-mono">${p.doc}</span>
<span class="text-gray-700 flex-1">${p.nombre}</span>
</div>
`).join('') + (data.hay_mas ? '<div class="px-4 py-2 text-xs text-gray-400">... y más pacientes</div>' : '');
table.innerHTML = data.pacientes_preview.map((p, i) => {
const rdaRows = p.rda.map(r => `
<div class="flex items-center gap-3 px-6 py-1.5 bg-blue-50 border-t border-blue-100 text-xs">
<span class="text-blue-400 w-4"><i class="fas fa-flask"></i></span>
<span class="font-mono text-blue-700 w-28">${r.factura}</span>
<span class="text-blue-600 w-24">${r.fecha}</span>
<span class="text-blue-600 w-20">${r.examenes} examen(es)</span>
<span class="text-blue-600 flex-1">${r.diag}</span>
<span class="text-blue-700 font-medium">$${r.valor.toLocaleString('es-CO')}</span>
</div>`).join('');
return `
<div class="divide-y divide-gray-100">
<div class="flex items-center gap-3 px-4 py-2.5 hover:bg-gray-50 cursor-pointer select-none"
onclick="toggleRda('rda-${i}', this)">
<i class="fas fa-chevron-right text-gray-300 text-xs transition-transform duration-150" id="chev-${i}"></i>
<span class="text-gray-400 text-xs w-8">${p.tipo}</span>
<span class="text-gray-500 w-32 font-mono text-xs">${p.doc}</span>
<span class="text-gray-700 flex-1">${p.nombre}</span>
<span class="text-xs ${p.rda.length > 0 ? 'text-blue-600' : 'text-gray-300'}">
${p.rda.length} RDA
</span>
</div>
<div id="rda-${i}" class="hidden">${rdaRows || '<div class="px-6 py-2 text-xs text-gray-400 bg-gray-50">Sin recepciones en esta fecha</div>'}</div>
</div>`;
}).join('');
document.getElementById('btn-run').disabled = false;
showToast(`${data.pacientes} paciente(s) y ${data.recepciones} recepción(es) encontradas`, 'success');
showToast(`${data.pacientes} paciente(s) · ${data.recepciones} recepción(es)`, 'success');
}
document.getElementById('preview-section').classList.remove('hidden');
@@ -206,6 +225,14 @@ async function runAutomation() {
}
}
function toggleRda(id, row) {
const div = document.getElementById(id);
const chev = row.querySelector('[id^="chev-"]');
const hidden = div.classList.contains('hidden');
div.classList.toggle('hidden', !hidden);
if (chev) chev.style.transform = hidden ? 'rotate(90deg)' : '';
}
function renderBadge(id, enviados, errores) {
const el = document.getElementById(id);
if (errores === 0) {