This commit is contained in:
Lizandro Guarnizo
2026-06-16 16:55:22 -05:00
parent a4a062095e
commit ff8454fa5a
5 changed files with 160 additions and 7 deletions
+29 -1
View File
@@ -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,
+2
View File
@@ -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(_) {}
},
};
@@ -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';
@@ -0,0 +1,99 @@
<?php
/**
* POST /modules/turnero/api/crear_envio_presencial.php
*
* Crea (o recupera) un registro lab_form_envios vinculado a un turnero_consentimientos
* para que el paciente pueda firmar presencialmente via form_cliente.php?t=TOKEN.
*
* Body JSON:
* consent_token string UUID del turnero_consentimientos (requerido)
*/
require_once __DIR__ . '/_helpers.php';
requireMethod('POST');
$datos = inputJson();
$consentToken = trim($datos['consent_token'] ?? '');
if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $consentToken)) {
jsonError('consent_token inválido.');
}
$pdo = db();
// ── 1. Cargar el consentimiento con datos del turno y paciente ────────
$stmt = $pdo->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]);
+20 -6
View File
@@ -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() {