Corregir Tomas Prolongadas: filtrado de secciones, firmante por toma, detalle en historial

Tres bugs relacionados en el formulario "Control de Tomas de Muestras
Prolongadas" (F-LAB-28), detectados en el turno E017:

1. El modal de documentos del historial abría el documento sin &embed=1,
   por lo que el filtrado de tomas irrelevantes (según examen seleccionado)
   nunca se aplicaba — se mostraban las 16 secciones posibles en vez de
   solo las 2-3 que aplicaban, con textos "Pendiente de firma" de más.

2. El guardado de firma en tomas progresivas usa un endpoint distinto
   (_guardarFirmaMP → guardar_toma.php) que no pasaba por el fix de
   nombre/cédula del firmante aplicado antes solo a _guardarFirmaPro.
   Como además una toma progresiva puede pasar por varios profesionales
   en el transcurso de horas, ahora se guarda identidad por-toma
   (campoId + '_pro_nombre'/'_pro_cedula'), no solo global.

3. El historial no mostraba quién atendió cada toma. get_consentimientos.php
   ahora expone tomas_detalle (etiqueta, hora, firmante) por consentimiento
   de toma progresiva, y el panel de documentos del historial lo renderiza
   en una tabla debajo del pill del formulario.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-08-03 14:26:28 -05:00
co-authored by Claude Sonnet 4.6
parent ec552136bf
commit 2ba13add34
3 changed files with 43 additions and 7 deletions
+24 -3
View File
@@ -87,9 +87,12 @@ foreach ($consentimientos as &$c) {
if ($esTomaProg) {
// Mapear cada firma_profesional a los valores de examen de su sección condicional
// (y a su etiqueta + campo hora, para poder mostrar el detalle por toma)
$firmaCondMap = [];
$curCondCampo = null;
$curCondVals = [];
$curLabel = null;
$curHoraId = null;
foreach ($campos as $campo) {
$ft = $campo['tipo'] ?? '';
if ($ft === 'separador') {
@@ -98,8 +101,15 @@ foreach ($consentimientos as &$c) {
$curCondVals = $cond
? ($cond['valores'] ?? ($cond['valor'] ? [$cond['valor']] : []))
: [];
$curLabel = $campo['label'] ?? '';
$curHoraId = null;
} elseif ($ft === 'hora') {
$curHoraId = $campo['id'] ?? null;
} elseif ($ft === 'firma_profesional' && !empty($campo['id'])) {
$firmaCondMap[$campo['id']] = ['campo' => $curCondCampo, 'valores' => $curCondVals];
$firmaCondMap[$campo['id']] = [
'campo' => $curCondCampo, 'valores' => $curCondVals,
'label' => $curLabel, 'hora_id' => $curHoraId,
];
}
}
@@ -133,9 +143,19 @@ foreach ($consentimientos as &$c) {
}
$tomasTotal = count($relevantIds);
$tomasDetalle = [];
foreach ($relevantIds as $fid) {
if ((!empty($dr[$fid]) && strlen($dr[$fid]) > 10)
|| (!empty($dr[$fid.'_svg']) && strlen($dr[$fid.'_svg']) > 10)) $tomasFirm++;
$firmado = (!empty($dr[$fid]) && strlen($dr[$fid]) > 10)
|| (!empty($dr[$fid.'_svg']) && strlen($dr[$fid.'_svg']) > 10);
if ($firmado) $tomasFirm++;
$info = $firmaCondMap[$fid] ?? [];
$horaId = $info['hora_id'] ?? null;
$tomasDetalle[] = [
'label' => $info['label'] ?? '',
'hora' => $horaId ? ($dr[$horaId] ?? null) : null,
'firmado' => $firmado,
'firmante' => $firmado ? ($dr[$fid . '_pro_nombre'] ?? $dr['_pro_nombre'] ?? null) : null,
];
}
}
@@ -147,6 +167,7 @@ foreach ($consentimientos as &$c) {
$c['es_toma_progresiva'] = $esTomaProg;
$c['tomas_total'] = $tomasTotal;
$c['tomas_firmadas'] = $tomasFirm;
$c['tomas_detalle'] = $tomasDetalle ?? [];
$c['cierre_anticipado'] = $dr['_cierre_anticipado'] ?? null;
// Exponer campos firma_profesional (ids) para el frontend
$c['campos_firma_pro'] = array_column($camposFirmaPro, 'id');
+14 -2
View File
@@ -631,7 +631,7 @@ async function cargarDocumentosTurno(turnoId, container) {
? ` <span class="badge bg-danger-subtle text-danger ms-1" style="font-size:.62rem">${c.tomas_firmadas||0}/${c.tomas_total||0} tomas</span>`
: '';
if (est === 'firmado' && c.token) {
const url = BASE_URL_ROOT + 'ver_formulario_enviado.php?token=' + encodeURIComponent(c.token);
const url = BASE_URL_ROOT + 'ver_formulario_enviado.php?token=' + encodeURIComponent(c.token) + '&embed=1';
return `<a class="doc-pill firmado" href="${url}" onclick="return abrirDocModal(event,'${url}','${nombre.replace(/'/g,"\\'")}')">
<i class="fas fa-check-circle"></i>${nombre}${tomas}
</a>`;
@@ -640,7 +640,19 @@ async function cargarDocumentosTurno(turnoId, container) {
const ico = est === 'enviado' ? 'fa-paper-plane' : (est === 'visto' ? 'fa-eye' : 'fa-clock');
return `<span class="doc-pill ${cls}"><i class="fas ${ico}"></i>${nombre}${tomas}</span>`;
}).join('');
container.innerHTML = '<div class="docs-lbl"><i class="fas fa-file-signature me-1"></i>Documentos</div>' + pills;
// Detalle por toma (quién atendió cada una) para formularios de tomas progresivas
const detalles = list.filter(c => c.es_toma_progresiva && c.tomas_detalle && c.tomas_detalle.length)
.map(c => `<table class="table table-sm mb-2" style="font-size:.76rem">
<thead><tr><th>${esc(c.formulario_nombre||'')}</th><th>Hora</th><th>Atendió</th></tr></thead>
<tbody>${c.tomas_detalle.map(t => `<tr class="${t.firmado ? '' : 'text-muted'}">
<td>${esc((t.label||'').replace(/^Toma\s*·\s*/,''))}</td>
<td>${esc(t.hora || '—')}</td>
<td>${t.firmado ? esc(t.firmante || '—') : '<i class="fas fa-clock"></i> pendiente'}</td>
</tr>`).join('')}</tbody>
</table>`).join('');
container.innerHTML = '<div class="docs-lbl"><i class="fas fa-file-signature me-1"></i>Documentos</div>' + pills + detalles;
} catch(_) {
const sp = container.querySelector('span');
if (sp) sp.textContent = 'Error de conexión';
+5 -2
View File
@@ -1111,8 +1111,8 @@ function _addExamWizardHtml(string $cid): string {
<img src="<?= htmlspecialchars($fSvg) ?>" alt="<?= $fLabel ?>">
</div>
<?php if ($isPro):
$_pn = $datosCliente['_pro_nombre'] ?? $profNombre ?? null;
$_pd = $datosCliente['_pro_cedula'] ?? $profDocumento ?? null;
$_pn = $datosCliente[$cid . '_pro_nombre'] ?? $datosCliente['_pro_nombre'] ?? $profNombre ?? null;
$_pd = $datosCliente[$cid . '_pro_cedula'] ?? $datosCliente['_pro_cedula'] ?? $profDocumento ?? null;
if ($_pn || $_pd): ?>
<div class="firma-pro-ident" style="font-size:13px;line-height:1.5;margin-top:4px">
<?php if ($_pn): ?><strong><?= esc2($_pn) ?></strong><br><?php endif; ?>
@@ -2354,6 +2354,9 @@ function _guardarFirmaMP(widget, svg, msgEl, entry, campoId) {
Object.assign(dr, window._mpSavedFirmas || {});
// Guardar con campoId directo (sin _svg) para que get_consentimientos lo cuente
dr[campoId] = svg;
// Identidad del firmante por toma (puede cambiar de profesional entre tomas)
if (window._profNombre) { dr[campoId + '_pro_nombre'] = window._profNombre; dr['_pro_nombre'] = window._profNombre; }
if (window._profDocumento) { dr[campoId + '_pro_cedula'] = window._profDocumento; dr['_pro_cedula'] = window._profDocumento; }
(window._mpSavedFirmas = window._mpSavedFirmas||{})[campoId] = svg;
// Fix 5: cachear hora en el momento de guardar para el resumen final
(window._mpTomaData = window._mpTomaData||{})[campoId] = {