From c9ea76f782918239fca7cc08ddd97b81bbec0646 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Tue, 28 Jul 2026 00:29:32 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20cierre=20anticipado=20de=20tomas=20prol?= =?UTF-8?q?ongadas=20con=20justificaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DB: añade estado 'cerrado_anticipado' al enum de turnero_consentimientos - ver_formulario_enviado.php: POST handler mp_cerrar_anticipado guarda motivo en _cierre_anticipado y cambia estado; botón "Cerrar anticipadamente" con modal textarea; bloque display para estado cerrado_anticipado mostrando el motivo; modoEditar y check de estado actualizados para excluir cerrado_anticipado - get_consentimientos.php: expone cierre_anticipado en respuesta; mueve parse de datos_respuestas fuera del if(esTomaProg) para ambos loops - lugar.php: CONSENT_IC/LBL incluye cerrado_anticipado; ya[] lo incluye; hayPendientes lo excluye; fila muestra motivo en banner amarillo - recepcion.php: CONSENT_META incluye cerrado_anticipado; ya[] lo incluye; motivo visible en la tarjeta del consentimiento Co-Authored-By: Claude Sonnet 4.6 --- modules/turnero/api/get_consentimientos.php | 6 +- modules/turnero/views/lugar.php | 31 ++++-- modules/turnero/views/recepcion.php | 18 ++-- ver_formulario_enviado.php | 106 +++++++++++++++++++- 4 files changed, 139 insertions(+), 22 deletions(-) diff --git a/modules/turnero/api/get_consentimientos.php b/modules/turnero/api/get_consentimientos.php index bf527ad..74befbb 100644 --- a/modules/turnero/api/get_consentimientos.php +++ b/modules/turnero/api/get_consentimientos.php @@ -81,10 +81,10 @@ foreach ($consentimientos as &$c) { // Toma progresiva: override explícito en DB gana; si es NULL, usar heurística (>1 campo firma_profesional) $overrideProg = $c['formulario_es_toma_prog'] ?? null; $esTomaProg = $overrideProg !== null ? (bool)(int)$overrideProg : count($camposFirmaPro) > 1; + $dr = $c['datos_respuestas'] ? (json_decode($c['datos_respuestas'], true) ?? []) : []; $tomasTotal = 0; $tomasFirm = 0; if ($esTomaProg) { - $dr = $c['datos_respuestas'] ? (json_decode($c['datos_respuestas'], true) ?? []) : []; // Mapear cada firma_profesional a los valores de examen de su sección condicional $firmaCondMap = []; @@ -147,6 +147,7 @@ foreach ($consentimientos as &$c) { $c['es_toma_progresiva'] = $esTomaProg; $c['tomas_total'] = $tomasTotal; $c['tomas_firmadas'] = $tomasFirm; + $c['cierre_anticipado'] = $dr['_cierre_anticipado'] ?? null; // Exponer campos firma_profesional (ids) para el frontend $c['campos_firma_pro'] = array_column($camposFirmaPro, 'id'); unset($c['formulario_esquema'], $c['formulario_es_toma_prog'], $c['formulario_solo_profesional'], $c['datos_respuestas']); @@ -333,10 +334,10 @@ if ($incluirSolicitud) { $tieneFirmaPac = !empty(array_filter($campos, fn($f) => ($f['tipo'] ?? '') === 'firma')); $overrideProg = $c['formulario_es_toma_prog'] ?? null; $esTomaProg = $overrideProg !== null ? (bool)(int)$overrideProg : count($camposFirmaPro) > 1; + $dr2 = $c['datos_respuestas'] ? (json_decode($c['datos_respuestas'], true) ?? []) : []; $tomasTotal2 = 0; $tomasFirm = 0; if ($esTomaProg) { - $dr2 = $c['datos_respuestas'] ? (json_decode($c['datos_respuestas'], true) ?? []) : []; $firmaCondMap2 = []; $curC2 = null; $curV2 = []; foreach ($campos as $campo2) { @@ -384,6 +385,7 @@ if ($incluirSolicitud) { $c['es_toma_progresiva'] = $esTomaProg; $c['tomas_total'] = $tomasTotal2; $c['tomas_firmadas'] = $tomasFirm; + $c['cierre_anticipado'] = $dr2['_cierre_anticipado'] ?? null; $c['campos_firma_pro'] = array_column($camposFirmaPro, 'id'); unset($c['formulario_esquema'], $c['formulario_es_toma_prog'], $c['formulario_solo_profesional'], $c['datos_respuestas']); } diff --git a/modules/turnero/views/lugar.php b/modules/turnero/views/lugar.php index 279238f..350b7f6 100644 --- a/modules/turnero/views/lugar.php +++ b/modules/turnero/views/lugar.php @@ -386,7 +386,8 @@ foreach ($lugares as $_el) { padding: .5rem .7rem; border-radius: 10px; margin-bottom: .35rem; font-size: .84rem; border: 1px solid transparent; min-height: 46px; } - .consent-row.firmado { background: #f0fdf4; color: #166534; border-color: #bbf7d0; } + .consent-row.firmado { background: #f0fdf4; color: #166534; border-color: #bbf7d0; } + .consent-row.cerrado_anticipado { background: #fef9c3; color: #78350f; border-color: #fde68a; } .consent-row.rechazado { background: #f8fafc; color: #64748b; border-color: #e2e8f0; } .consent-row.enviado { background: #eff6ff; color: #1e40af; border-color: #bfdbfe; } .consent-row.pendiente { background: #fffbeb; color: #92400e; border-color: #fde68a; } @@ -1394,10 +1395,11 @@ const CONSENT_IC = { firmado:'fa-check-circle', rechazado:'fa-ban', enviado:'fa-envelope', visto:'fa-eye', pendiente:'fa-clock', en_progreso:'fa-hourglass-half', + cerrado_anticipado:'fa-exclamation-triangle', }; const CONSENT_LBL = { firmado:'Firmado', rechazado:'Rechazado', enviado:'Enviado', visto:'Visto', pendiente:'Pendiente', - en_progreso:'En progreso', + en_progreso:'En progreso', cerrado_anticipado:'Cerrado anticipadamente', }; // ── Countdown en tarjetas de cola (toma progresiva) ────────── @@ -1530,7 +1532,7 @@ function renderConsentimientos(lista) { // Mostrar consentimientos de examen (origen null) + los de esta estación lista = lista.filter(c => !c.origen_lugar_id || c.origen_lugar_id == lugarId); tieneConsent = lista.length > 0; - hayPendientes = lista.some(c => !['firmado','rechazado'].includes(c.estado)); + hayPendientes = lista.some(c => !['firmado','rechazado','cerrado_anticipado'].includes(c.estado)); // en_progreso bloquea finalizar pero no muestra aviso de "pendiente sin acción" const pendCount = lista.filter(c => ['pendiente','enviado','visto'].includes(c.estado)).length; @@ -1574,7 +1576,7 @@ function renderConsentimientos(lista) { } listEl.innerHTML = lista.map(c => { - const ya = ['firmado','rechazado'].includes(c.estado); + const ya = ['firmado','rechazado','cerrado_anticipado'].includes(c.estado); const ico = CONSENT_IC[c.estado] || 'fa-clock'; const label = CONSENT_LBL[c.estado] || c.estado; const token = escHtml(c.token || ''); @@ -1631,13 +1633,20 @@ function renderConsentimientos(lista) { `; - return `
+ + +
+ +
+ Toma cerrada anticipadamente
+ +
+ +
+ + +
+
@@ -1377,6 +1406,29 @@ function _addExamWizardHtml(string $cid): string {
+ +
+ +
+ + + +