diff --git a/api/lab/submit_formulario.php b/api/lab/submit_formulario.php index 413a506..f062bab 100644 --- a/api/lab/submit_formulario.php +++ b/api/lab/submit_formulario.php @@ -118,7 +118,35 @@ try { // Recuperar hash e id para la respuesta $db = Database::getInstance(); - $saved = $db->fetch('SELECT id, hash_verificacion FROM lab_form_envios WHERE token = ?', [$token]); + $saved = $db->fetch('SELECT id, hash_verificacion, turnero_consentimiento_id FROM lab_form_envios WHERE token = ?', [$token]); + + // Si este envío está vinculado a un consentimiento del turnero, marcarlo como firmado + if (!empty($saved['turnero_consentimiento_id'])) { + $pdo2 = $db->getConnection(); + $tc = $pdo2->prepare( + "SELECT tc.id, t.sesion_id FROM turnero_consentimientos tc + JOIN turnero_turnos t ON t.id = tc.turno_id + WHERE tc.id = ? AND tc.estado != 'firmado'" + ); + $tc->execute([(int)$saved['turnero_consentimiento_id']]); + $tcRow = $tc->fetch(PDO::FETCH_ASSOC); + if ($tcRow) { + $datosRespuestasJson = !empty($datosCliente) + ? json_encode($datosCliente, JSON_UNESCAPED_UNICODE) + : null; + $pdo2->prepare( + "UPDATE turnero_consentimientos + SET estado='firmado', firmado_at=NOW(), firma_svg=?, + ip_firma=?, ua_firma=?, datos_respuestas=? + WHERE id=?" + )->execute([$firmaSvg, $ip, substr($ua, 0, 500), $datosRespuestasJson, (int)$tcRow['id']]); + // Notificar via SSE para actualizar lugar.php en tiempo real + if ($tcRow['sesion_id']) { + require_once __DIR__ . '/../../modules/turnero/api/_helpers.php'; + notificarSSE((int)$tcRow['sesion_id']); + } + } + } pubOk([ 'firmado' => (bool)$firmaSvg, diff --git a/form_cliente.php b/form_cliente.php index fd8270a..b5ebfae 100644 --- a/form_cliente.php +++ b/form_cliente.php @@ -1088,6 +1088,8 @@ const formCliente = { } show('success-screen'); window.scrollTo({top: 0, behavior: 'smooth'}); + // Notificar al frame padre si estamos en modo presencial del turnero + try { window.parent.postMessage({ type: 'turneroFirmado' }, '*'); } catch(_) {} }, }; diff --git a/migrations/20260616_lab_form_envios_turnero.sql b/migrations/20260616_lab_form_envios_turnero.sql new file mode 100644 index 0000000..66333ec --- /dev/null +++ b/migrations/20260616_lab_form_envios_turnero.sql @@ -0,0 +1,10 @@ +-- Vincula lab_form_envios con turnero_consentimientos para firma presencial +ALTER TABLE lab_form_envios + ADD COLUMN IF NOT EXISTS turnero_consentimiento_id INT UNSIGNED DEFAULT NULL + COMMENT 'FK turnero_consentimientos.id cuando es firma presencial del turnero', + ADD INDEX IF NOT EXISTS idx_fenv_tc (turnero_consentimiento_id); + +-- Vinculo inverso: el consentimiento sabe cuál lab_form_envios usa para firma presencial +ALTER TABLE turnero_consentimientos + ADD COLUMN IF NOT EXISTS lab_form_envio_id INT DEFAULT NULL + COMMENT 'FK lab_form_envios.id para firma presencial via form_cliente.php'; diff --git a/modules/turnero/api/crear_envio_presencial.php b/modules/turnero/api/crear_envio_presencial.php new file mode 100644 index 0000000..64eb9d5 --- /dev/null +++ b/modules/turnero/api/crear_envio_presencial.php @@ -0,0 +1,99 @@ +prepare( + "SELECT tc.id AS tc_id, + tc.formulario_id, + tc.token AS tc_token, + tc.estado, + tc.lab_form_envio_id, + ts.paciente_id, + t.sesion_id, + p.nombre_completo, p.tipo_documento, p.numero_documento, + p.fecha_nacimiento, p.telefono, p.eps + FROM turnero_consentimientos tc + JOIN turnero_turnos t ON t.id = tc.turno_id + LEFT JOIN turnero_solicitudes ts ON ts.turno_id = tc.turno_id + LEFT JOIN lab_pacientes p ON p.id = ts.paciente_id + WHERE tc.token = ? + LIMIT 1" +); +$stmt->execute([$consentToken]); +$tc = $stmt->fetch(PDO::FETCH_ASSOC); + +if (!$tc) jsonError('Consentimiento no encontrado.', 404); + +// ── Si ya fue firmado o tiene envío vinculado, devolver ese token ──── +if ($tc['lab_form_envio_id']) { + $stEnv = $pdo->prepare("SELECT token, estado FROM lab_form_envios WHERE id = ?"); + $stEnv->execute([(int)$tc['lab_form_envio_id']]); + $envio = $stEnv->fetch(PDO::FETCH_ASSOC); + if ($envio) { + // Si el envio no fue completado todavía, reutilizarlo + if (!in_array($envio['estado'], ['completado', 'firmado'])) { + jsonOk(['form_token' => $envio['token']]); + } + // Si ya completado, devolver igualmente el token para que el operador lo vea + jsonOk(['form_token' => $envio['token'], 'ya_firmado' => true]); + } +} + +if ($tc['estado'] === 'firmado') { + jsonError('Este consentimiento ya fue firmado.', 409); +} + +// ── 3. Crear nuevo lab_form_envios ──────────────────────────────────── +$formToken = bin2hex(random_bytes(32)); // 64 chars hex + +$prefilled = []; +if ($tc['nombre_completo']) $prefilled['__paciente']['nombre_completo'] = $tc['nombre_completo']; +if ($tc['tipo_documento']) $prefilled['__paciente']['tipo_documento'] = $tc['tipo_documento']; +if ($tc['numero_documento']) $prefilled['__paciente']['numero_documento'] = $tc['numero_documento']; +if ($tc['fecha_nacimiento']) $prefilled['__paciente']['fecha_nacimiento'] = $tc['fecha_nacimiento']; +if ($tc['telefono']) $prefilled['__paciente']['telefono'] = $tc['telefono']; +if ($tc['eps']) $prefilled['__paciente']['eps'] = $tc['eps']; + +$userId = (int)($_SESSION['admin_user']['id'] ?? 0) ?: null; + +$ins = $pdo->prepare( + "INSERT INTO lab_form_envios + (formulario_id, paciente_id, token, datos_prefilled, estado, enviado_por, enviado_via, turnero_consentimiento_id) + VALUES (?, ?, ?, ?, 'pendiente', ?, 'link', ?)" +); +$ins->execute([ + (int)$tc['formulario_id'], + $tc['paciente_id'] ?: null, + $formToken, + json_encode($prefilled, JSON_UNESCAPED_UNICODE), + $userId, + (int)$tc['tc_id'], +]); + +$formEnvioId = (int)$pdo->lastInsertId(); + +// ── 4. Guardar el vínculo en turnero_consentimientos ───────────────── +$pdo->prepare("UPDATE turnero_consentimientos SET lab_form_envio_id = ? WHERE id = ?") + ->execute([$formEnvioId, (int)$tc['tc_id']]); + +jsonOk(['form_token' => $formToken]); diff --git a/modules/turnero/views/lugar.php b/modules/turnero/views/lugar.php index a7f58bd..0033223 100644 --- a/modules/turnero/views/lugar.php +++ b/modules/turnero/views/lugar.php @@ -715,14 +715,28 @@ async function reenviarConsentimiento(turnoId) { } // ── Modal de firma presencial ───────────────────────────────── -function abrirFirmaPresencial(token, consentId, nombreForm) { - const url = BASE_WA + 'ver_formulario_enviado.php?token=' + encodeURIComponent(token); - document.getElementById('modal-firma-titulo').textContent = 'Firmar: ' + nombreForm; - document.getElementById('firma-iframe').src = url; +async function abrirFirmaPresencial(token, consentId, nombreForm) { + document.getElementById('modal-firma-titulo').textContent = 'Cargando…'; + document.getElementById('firma-iframe').src = ''; document.getElementById('modal-firma').classList.add('open'); - - // Al cerrar, refrescar consentimientos window._firmaConsentId = consentId; + + try { + const res = await fetch(API + 'crear_envio_presencial.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ consent_token: token }), + }); + const json = await res.json(); + if (!json.ok || !json.form_token) throw new Error(json.error || 'Error al crear envío'); + document.getElementById('modal-firma-titulo').textContent = 'Firmar: ' + nombreForm; + document.getElementById('firma-iframe').src = BASE_WA + 'form_cliente.php?t=' + encodeURIComponent(json.form_token); + } catch (err) { + document.getElementById('modal-firma-titulo').textContent = 'Error'; + document.getElementById('firma-iframe').src = ''; + alert('No se pudo cargar el formulario: ' + err.message); + cerrarModalFirma(); + } } function cerrarModalFirma() {