up
This commit is contained in:
@@ -1,10 +0,0 @@
|
|||||||
-- ============================================================
|
|
||||||
-- Migration: 20260611_turnero_consentimiento_principal
|
|
||||||
-- Añade flag is_principal a lab_formularios para marcar
|
|
||||||
-- el consentimiento principal de recepción (no ligado a exámenes).
|
|
||||||
-- ============================================================
|
|
||||||
|
|
||||||
ALTER TABLE lab_formularios
|
|
||||||
ADD COLUMN is_principal TINYINT(1) NOT NULL DEFAULT 0
|
|
||||||
COMMENT '1 = consentimiento principal de recepción, se auto-crea al tomar turno'
|
|
||||||
AFTER tipo;
|
|
||||||
@@ -98,67 +98,48 @@ try {
|
|||||||
|
|
||||||
notificarSSE($sesionId);
|
notificarSSE($sesionId);
|
||||||
|
|
||||||
// ── Auto-crear consentimiento principal + enviar WhatsApp ──
|
// ── Enviar notificación WhatsApp con la plantilla configurada ──
|
||||||
try {
|
if ($pacienteTel) {
|
||||||
$stmtPc = $pdo->prepare(
|
try {
|
||||||
"SELECT id, nombre FROM lab_formularios WHERE is_principal = 1 AND tipo = 'consentimiento' AND is_active = 1 LIMIT 1"
|
$stmtCfg = $pdo->prepare(
|
||||||
);
|
"SELECT clave, valor FROM lab_config WHERE clave IN ('turnero_wa_template','turnero_wa_lang')"
|
||||||
$stmtPc->execute();
|
|
||||||
$principalForm = $stmtPc->fetch(PDO::FETCH_ASSOC);
|
|
||||||
if ($principalForm) {
|
|
||||||
$tokenPrincipal = sprintf(
|
|
||||||
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
|
||||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
|
|
||||||
mt_rand(0, 0xffff),
|
|
||||||
mt_rand(0, 0x0fff) | 0x4000,
|
|
||||||
mt_rand(0, 0x3fff) | 0x8000,
|
|
||||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
|
|
||||||
);
|
);
|
||||||
$stmtIns = $pdo->prepare(
|
$stmtCfg->execute();
|
||||||
"INSERT IGNORE INTO turnero_consentimientos (turno_id, formulario_id, token, estado)
|
$cfgWA = $stmtCfg->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||||
VALUES (?, ?, ?, 'pendiente')"
|
$waTemplate = $cfgWA['turnero_wa_template'] ?? 'consentimiento_turno';
|
||||||
);
|
$waLang = $cfgWA['turnero_wa_lang'] ?? 'es_CO';
|
||||||
$stmtIns->execute([$turnoId, (int)$principalForm['id'], $tokenPrincipal]);
|
} catch (\Throwable $e) {
|
||||||
|
$waTemplate = 'consentimiento_turno';
|
||||||
|
$waLang = 'es_CO';
|
||||||
|
}
|
||||||
|
|
||||||
// Enviar WhatsApp si tenemos celular
|
$cel = preg_replace('/[\s\-\.]/', '', $pacienteTel);
|
||||||
if ($pacienteTel) {
|
if (!str_starts_with($cel, '+')) {
|
||||||
$cel = preg_replace('/[\s\-\.]/', '', $pacienteTel);
|
$cel = '+57' . ltrim($cel, '0');
|
||||||
if (!str_starts_with($cel, '+')) {
|
}
|
||||||
$cel = '+57' . ltrim($cel, '0');
|
$nombrePacWA = $pacienteNombre ?: 'Paciente';
|
||||||
}
|
require_once __DIR__ . '/../../../services/WhatsAppService.php';
|
||||||
$enlaceFirma = (defined('BASE_URL') ? rtrim(BASE_URL, '/') : '')
|
try {
|
||||||
. '/ver_formulario_enviado.php?token=' . urlencode($tokenPrincipal);
|
$wa = new WhatsAppService();
|
||||||
$nombrePacWA = $pacienteNombre ?: 'Paciente';
|
$wa->sendTemplateMessage(
|
||||||
require_once __DIR__ . '/../../../services/WhatsAppService.php';
|
$cel,
|
||||||
try {
|
$waTemplate,
|
||||||
$wa = new WhatsAppService();
|
$waLang,
|
||||||
$wa->sendTemplateMessage(
|
[
|
||||||
$cel,
|
htmlspecialchars($nombrePacWA, ENT_QUOTES),
|
||||||
'consentimiento_turno',
|
$codigo,
|
||||||
'es',
|
'',
|
||||||
[
|
],
|
||||||
htmlspecialchars($nombrePacWA, ENT_QUOTES),
|
[]
|
||||||
htmlspecialchars($principalForm['nombre'], ENT_QUOTES),
|
);
|
||||||
$codigo,
|
} catch (\Throwable $eTmpl) {
|
||||||
],
|
try {
|
||||||
[$enlaceFirma]
|
$mensajeTexto = "Hola {$nombrePacWA}, su turno *{$codigo}* ha sido registrado en {$codigo}. Preséntese al laboratorio.";
|
||||||
);
|
$wa->sendTextMessage($cel, $mensajeTexto);
|
||||||
} catch (\Throwable $eTmpl) {
|
} catch (\Throwable $eTxt) {
|
||||||
try {
|
// Silenciar
|
||||||
$mensajeTexto = "Hola {$nombrePacWA}, le informamos que para su turno *{$codigo}* "
|
|
||||||
. "debe firmar el siguiente consentimiento informado:\n\n"
|
|
||||||
. "*{$principalForm['nombre']}*\n\n"
|
|
||||||
. "Puede firmarlo en el siguiente enlace:\n{$enlaceFirma}\n\n"
|
|
||||||
. "Si ya firmó este documento presencial, ignore este mensaje.";
|
|
||||||
$wa->sendTextMessage($cel, $mensajeTexto);
|
|
||||||
} catch (\Throwable $eTxt) {
|
|
||||||
// Silenciar error de WhatsApp, el turno ya se creó
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// Silenciar error — el turno ya se creó exitosamente
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contar posición en la cola
|
// Contar posición en la cola
|
||||||
|
|||||||
@@ -117,28 +117,6 @@ if ($lugarIdSol > 0) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3c. Consentimiento principal de recepción (is_principal)
|
|
||||||
$principalRow = null;
|
|
||||||
try {
|
|
||||||
$stmtPc = $pdo->prepare(
|
|
||||||
"SELECT id AS formulario_id, nombre AS formulario_nombre
|
|
||||||
FROM lab_formularios
|
|
||||||
WHERE is_principal = 1 AND tipo = 'consentimiento' AND is_active = 1
|
|
||||||
LIMIT 1"
|
|
||||||
);
|
|
||||||
$stmtPc->execute();
|
|
||||||
$principalRow = $stmtPc->fetch(PDO::FETCH_ASSOC);
|
|
||||||
} catch (\Throwable $e) {}
|
|
||||||
if ($principalRow) {
|
|
||||||
$yaExiste = false;
|
|
||||||
foreach ($formulariosRequeridos as $fr) {
|
|
||||||
if ((int)$fr['formulario_id'] === (int)$principalRow['formulario_id']) { $yaExiste = true; break; }
|
|
||||||
}
|
|
||||||
if (!$yaExiste) {
|
|
||||||
$formulariosRequeridos[] = $principalRow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($formulariosRequeridos)) {
|
if (empty($formulariosRequeridos)) {
|
||||||
jsonOk(['consentimientos' => [], 'mensaje' => 'Ningún examen ni servicio requiere consentimiento.']);
|
jsonOk(['consentimientos' => [], 'mensaje' => 'Ningún examen ni servicio requiere consentimiento.']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* modules/turnero/api/set_principal_consent.php
|
|
||||||
* POST { formulario_id: int | null }
|
|
||||||
* Marca un lab_formularios como consentimiento principal de recepción.
|
|
||||||
* Pasa null para desmarcar (ningún principal).
|
|
||||||
* Solo UN formulario puede ser principal a la vez.
|
|
||||||
*/
|
|
||||||
require_once __DIR__ . '/_helpers.php';
|
|
||||||
requireMethod('POST');
|
|
||||||
requireTurnero();
|
|
||||||
|
|
||||||
$input = inputJson();
|
|
||||||
$formularioId = isset($input['formulario_id']) ? (int) $input['formulario_id'] : null;
|
|
||||||
|
|
||||||
$pdo = db();
|
|
||||||
|
|
||||||
if ($formularioId) {
|
|
||||||
// Verificar que el formulario existe y es tipo consentimiento
|
|
||||||
$stmt = $pdo->prepare(
|
|
||||||
"SELECT id FROM lab_formularios WHERE id = ? AND tipo = 'consentimiento' AND is_active = 1"
|
|
||||||
);
|
|
||||||
$stmt->execute([$formularioId]);
|
|
||||||
if (!$stmt->fetch()) {
|
|
||||||
jsonError('Formulario no encontrado o no es un consentimiento activo.', 404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$pdo->beginTransaction();
|
|
||||||
try {
|
|
||||||
// Quitar principal de todos
|
|
||||||
$pdo->exec("UPDATE lab_formularios SET is_principal = 0 WHERE is_principal = 1");
|
|
||||||
// Marcar el nuevo principal (si aplica)
|
|
||||||
if ($formularioId) {
|
|
||||||
$stmt = $pdo->prepare("UPDATE lab_formularios SET is_principal = 1 WHERE id = ?");
|
|
||||||
$stmt->execute([$formularioId]);
|
|
||||||
}
|
|
||||||
$pdo->commit();
|
|
||||||
jsonOk([
|
|
||||||
'formulario_id' => $formularioId,
|
|
||||||
], $formularioId ? 'Consentimiento principal actualizado' : 'Consentimiento principal desmarcado');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$pdo->rollBack();
|
|
||||||
jsonError('Error al actualizar: ' . $e->getMessage(), 500);
|
|
||||||
}
|
|
||||||
@@ -58,7 +58,7 @@ try {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$formulariosCons = $pdo->query(
|
$formulariosCons = $pdo->query(
|
||||||
"SELECT id, nombre, COALESCE(is_principal,0) AS is_principal FROM lab_formularios WHERE is_active=1 ORDER BY nombre ASC"
|
"SELECT id, nombre FROM lab_formularios WHERE is_active=1 ORDER BY nombre ASC"
|
||||||
)->fetchAll(PDO::FETCH_ASSOC);
|
)->fetchAll(PDO::FETCH_ASSOC);
|
||||||
} catch (\Throwable $e) { $_loadErrors[] = 'lab_formularios: ' . $e->getMessage(); }
|
} catch (\Throwable $e) { $_loadErrors[] = 'lab_formularios: ' . $e->getMessage(); }
|
||||||
|
|
||||||
@@ -491,37 +491,16 @@ $tab = $_GET['tab'] ?? 'lugares';
|
|||||||
<?php if (!empty($formulariosCons)): ?>
|
<?php if (!empty($formulariosCons)): ?>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<p class="section-title"><i class="fas fa-file-signature me-1"></i>Vista inversa: por consentimiento</p>
|
<p class="section-title"><i class="fas fa-file-signature me-1"></i>Vista inversa: por consentimiento</p>
|
||||||
|
|
||||||
<div class="alert alert-info py-2 px-3 small mb-3" style="font-size:.8rem">
|
|
||||||
<i class="fas fa-star me-1 text-warning"></i>
|
|
||||||
Marque un consentimiento como <strong>principal</strong> (el que se firma en recepción para pasar a toma de muestras).
|
|
||||||
Se auto-creará cuando el paciente tome turno en el kiosko y se enviará por WhatsApp automáticamente.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php $principalEncontrado = false; ?>
|
|
||||||
<?php foreach ($formulariosCons as $fc):
|
<?php foreach ($formulariosCons as $fc):
|
||||||
$exsVinculados = [];
|
$exsVinculados = [];
|
||||||
foreach ($examTipos as $et) {
|
foreach ($examTipos as $et) {
|
||||||
$fids = $et['form_ids'] ? array_map('intval', explode(',', $et['form_ids'])) : [];
|
$fids = $et['form_ids'] ? array_map('intval', explode(',', $et['form_ids'])) : [];
|
||||||
if (in_array((int)$fc['id'], $fids)) $exsVinculados[] = $et;
|
if (in_array((int)$fc['id'], $fids)) $exsVinculados[] = $et;
|
||||||
}
|
}
|
||||||
$esPrincipal = !empty($fc['is_principal']);
|
|
||||||
if ($esPrincipal) $principalEncontrado = true;
|
|
||||||
?>
|
?>
|
||||||
<div class="mb-2 d-flex align-items-center gap-2" style="padding:4px 0">
|
<div class="mb-2">
|
||||||
<?php if ($esPrincipal): ?>
|
|
||||||
<span class="badge bg-warning text-dark" style="font-size:.65rem;cursor:pointer"
|
|
||||||
onclick="quitarPrincipalConsent(<?= (int)$fc['id'] ?>)" title="Quitar como principal">
|
|
||||||
<i class="fas fa-star"></i> Principal
|
|
||||||
</span>
|
|
||||||
<?php else: ?>
|
|
||||||
<span class="badge bg-light text-muted" style="font-size:.65rem;cursor:pointer"
|
|
||||||
onclick="marcarPrincipalConsent(<?= (int)$fc['id'] ?>)" title="Marcar como consentimiento principal">
|
|
||||||
<i class="far fa-star"></i>
|
|
||||||
</span>
|
|
||||||
<?php endif; ?>
|
|
||||||
<span class="fw-semibold small"><?= htmlspecialchars($fc['nombre']) ?></span>
|
<span class="fw-semibold small"><?= htmlspecialchars($fc['nombre']) ?></span>
|
||||||
<span class="text-muted small ms-1">
|
<span class="text-muted small ms-2">
|
||||||
<?= empty($exsVinculados)
|
<?= empty($exsVinculados)
|
||||||
? '<em>Sin exámenes vinculados</em>'
|
? '<em>Sin exámenes vinculados</em>'
|
||||||
: implode(', ', array_map(fn($e)=>'<code>'.$e['codigo'].'</code>', $exsVinculados))
|
: implode(', ', array_map(fn($e)=>'<code>'.$e['codigo'].'</code>', $exsVinculados))
|
||||||
@@ -529,11 +508,6 @@ $tab = $_GET['tab'] ?? 'lugares';
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php if (!$principalEncontrado): ?>
|
|
||||||
<div class="text-muted small">
|
|
||||||
<em>Ningún consentimiento marcado como principal.</em>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
@@ -1149,32 +1123,6 @@ async function borrarTvVideo() {
|
|||||||
} catch(e) { toast('Error de conexión', 'error'); }
|
} catch(e) { toast('Error de conexión', 'error'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Consentimiento principal ──────────────────────────────────
|
|
||||||
async function marcarPrincipalConsent(formularioId) {
|
|
||||||
try {
|
|
||||||
const res = await fetch(API + 'set_principal_consent.php', {
|
|
||||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ formulario_id: formularioId })
|
|
||||||
});
|
|
||||||
const json = await res.json();
|
|
||||||
if (!json.ok) { toast(json.error || 'Error', 'error'); return; }
|
|
||||||
toast('Consentimiento principal actualizado');
|
|
||||||
setTimeout(() => location.reload(), 400);
|
|
||||||
} catch (e) { toast('Error de conexión', 'error'); }
|
|
||||||
}
|
|
||||||
async function quitarPrincipalConsent() {
|
|
||||||
try {
|
|
||||||
const res = await fetch(API + 'set_principal_consent.php', {
|
|
||||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ formulario_id: null })
|
|
||||||
});
|
|
||||||
const json = await res.json();
|
|
||||||
if (!json.ok) { toast(json.error || 'Error', 'error'); return; }
|
|
||||||
toast('Consentimiento principal desmarcado');
|
|
||||||
setTimeout(() => location.reload(), 400);
|
|
||||||
} catch (e) { toast('Error de conexión', 'error'); }
|
|
||||||
}
|
|
||||||
|
|
||||||
async function guardarWhatsApp() {
|
async function guardarWhatsApp() {
|
||||||
const template = document.getElementById('wa-template')?.value.trim();
|
const template = document.getElementById('wa-template')?.value.trim();
|
||||||
const lang = document.getElementById('wa-lang')?.value.trim();
|
const lang = document.getElementById('wa-lang')?.value.trim();
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ $_hasVideo = (bool)$_tvVideo;
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.pg-body.has-video {
|
.pg-body.has-video {
|
||||||
grid-template-columns: 240px 1fr 240px;
|
grid-template-columns: 380px 1fr 380px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -594,21 +594,8 @@ function abrirFicha(turno) {
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cargar consentimientos anticipados (principal y otros ya creados)
|
// Buscar consentimientos si ya tiene solicitud
|
||||||
cargarConsentimientosTurno(turno.id);
|
verificarSolicitudExistente(turno.id);
|
||||||
}
|
|
||||||
|
|
||||||
async function cargarConsentimientosTurno(turnoId) {
|
|
||||||
try {
|
|
||||||
const res = await fetch(`${API}get_consentimientos.php?turno_id=${turnoId}`);
|
|
||||||
const json = await res.json();
|
|
||||||
if (json.ok && json.consentimientos?.length) {
|
|
||||||
consentimientos = json.consentimientos;
|
|
||||||
renderConsentimientos(consentimientos);
|
|
||||||
document.getElementById('sec-consentimientos').style.display = '';
|
|
||||||
document.getElementById('btn-reenviar-consent').classList.remove('d-none');
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function verificarSolicitudExistente(turnoId) {
|
async function verificarSolicitudExistente(turnoId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user