create_solicitud.php: cambia de crear consents por lugar (toma de muestras) a crear consents por examen (exam_tipo_consentimientos). Los de lugar se crean cuando el paciente llega a la estación vía get_consentimientos.php. get_consentimientos.php: cuando lugar_destino_id es NULL (turno en recepción), busca TODOS los formularios de turnero_lugar_consentimientos y los marca con origen_lugar_id = -1 (truthy), para que el filtro !c.origen_lugar_id de recepcion.php los excluya correctamente aunque no haya destino asignado aún. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
307 lines
13 KiB
PHP
307 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* GET /modules/turnero/api/get_consentimientos.php
|
|
* Retorna el estado actualizado de los consentimientos de un turno.
|
|
* Usado por lugar.php (polling cada 5 s) y recepcion.php.
|
|
* No requiere autenticación (las pantallas internas ya están protegidas).
|
|
*
|
|
* Query params:
|
|
* turno_id int requerido
|
|
* incluir_solicitud int opcional 1 → también retorna solicitud, paciente y exámenes
|
|
*/
|
|
|
|
require_once __DIR__ . '/_helpers.php';
|
|
requireMethod('GET');
|
|
|
|
$turnoId = isset($_GET['turno_id']) ? (int) $_GET['turno_id'] : 0;
|
|
$incluirSolicitud = isset($_GET['incluir_solicitud']) ? (bool)(int)$_GET['incluir_solicitud'] : false;
|
|
|
|
if ($turnoId <= 0) jsonError('turno_id inválido.');
|
|
|
|
$pdo = db();
|
|
|
|
// ── Verificar que el turno existe ─────────────────────────────
|
|
$stmt = $pdo->prepare("SELECT id, estado, lugar_destino_id FROM turnero_turnos WHERE id = ?");
|
|
$stmt->execute([$turnoId]);
|
|
$turno = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
if (!$turno) jsonError('Turno no encontrado.', 404);
|
|
|
|
// ── Formularios de lugar ──────────────────────────────────────────────────────
|
|
// Si el turno ya tiene lugar destino asignado, usar solo ese lugar.
|
|
// Si aún está en recepción (lugar_destino_id NULL), marcar como "de lugar" todos
|
|
// los formularios configurados en cualquier lugar para que recepcion.php los filtre
|
|
// con !c.origen_lugar_id aunque todavía no exista destino.
|
|
$lugarDestinoId = (int)($turno['lugar_destino_id'] ?? 0);
|
|
$fidsDeLugar = [];
|
|
if ($lugarDestinoId) {
|
|
$stmtL = $pdo->prepare(
|
|
"SELECT formulario_id FROM turnero_lugar_consentimientos WHERE lugar_id = ?"
|
|
);
|
|
$stmtL->execute([$lugarDestinoId]);
|
|
$fidsDeLugar = array_map('intval', $stmtL->fetchAll(PDO::FETCH_COLUMN));
|
|
} else {
|
|
$stmtL = $pdo->prepare(
|
|
"SELECT DISTINCT formulario_id FROM turnero_lugar_consentimientos"
|
|
);
|
|
$stmtL->execute();
|
|
$fidsDeLugar = array_map('intval', $stmtL->fetchAll(PDO::FETCH_COLUMN));
|
|
}
|
|
|
|
// ── Consentimientos ───────────────────────────────────────────
|
|
$stmt = $pdo->prepare(
|
|
"SELECT tc.id,
|
|
tc.turno_id,
|
|
tc.formulario_id,
|
|
tc.token,
|
|
tc.estado,
|
|
tc.enviado_at,
|
|
tc.firmado_at,
|
|
(tc.firma_profesional_svg IS NOT NULL) AS tiene_firma_profesional,
|
|
tc.firmado_profesional_at,
|
|
tc.siguiente_toma_at,
|
|
tc.toma_inicio_at,
|
|
tc.datos_respuestas,
|
|
f.nombre AS formulario_nombre,
|
|
f.esquema AS formulario_esquema
|
|
FROM turnero_consentimientos tc
|
|
LEFT JOIN lab_formularios f ON f.id = tc.formulario_id
|
|
WHERE tc.turno_id = ?
|
|
ORDER BY tc.id ASC"
|
|
);
|
|
$stmt->execute([$turnoId]);
|
|
$consentimientos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Compute flags desde el esquema; origen_lugar_id calculado según config actual
|
|
foreach ($consentimientos as &$c) {
|
|
$esquema = $c['formulario_esquema'] ?? null;
|
|
$campos = [];
|
|
if ($esquema) {
|
|
$decoded = json_decode($esquema, true);
|
|
$campos = is_array($decoded) ? $decoded : ($decoded['campos'] ?? []);
|
|
}
|
|
$camposFirmaPro = array_values(array_filter($campos, fn($f) => ($f['tipo'] ?? '') === 'firma_profesional'));
|
|
$tieneFirmaPro = !empty($camposFirmaPro);
|
|
$tieneFirmaPac = !empty(array_filter($campos, fn($f) => ($f['tipo'] ?? '') === 'firma'));
|
|
|
|
// Toma progresiva: más de 1 campo firma_profesional
|
|
$esTomaProg = count($camposFirmaPro) > 1;
|
|
$tomasTotal = count($camposFirmaPro);
|
|
$tomasFirm = 0;
|
|
if ($esTomaProg && $c['datos_respuestas']) {
|
|
$dr = json_decode($c['datos_respuestas'], true) ?? [];
|
|
foreach ($camposFirmaPro as $fp) {
|
|
if (!empty($dr[$fp['id']]) && strlen($dr[$fp['id']]) > 10) $tomasFirm++;
|
|
}
|
|
}
|
|
|
|
$c['requiere_firma_profesional'] = $tieneFirmaPro;
|
|
$c['requiere_firma_paciente'] = !($tieneFirmaPro && !$tieneFirmaPac);
|
|
$c['origen_lugar_id'] = in_array((int)$c['formulario_id'], $fidsDeLugar, true)
|
|
? ($lugarDestinoId ?: -1) : null;
|
|
$c['es_toma_progresiva'] = $esTomaProg;
|
|
$c['tomas_total'] = $tomasTotal;
|
|
$c['tomas_firmadas'] = $tomasFirm;
|
|
// Exponer campos firma_profesional (ids) para el frontend
|
|
$c['campos_firma_pro'] = array_column($camposFirmaPro, 'id');
|
|
unset($c['formulario_esquema'], $c['datos_respuestas']);
|
|
}
|
|
unset($c);
|
|
|
|
$respuesta = [
|
|
'turno_id' => $turnoId,
|
|
'turno_estado' => $turno['estado'],
|
|
'consentimientos' => $consentimientos,
|
|
];
|
|
|
|
// ── Datos adicionales si solicita solicitud ───────────────────
|
|
if ($incluirSolicitud) {
|
|
$stmt = $pdo->prepare(
|
|
"SELECT s.id, s.turno_id, s.paciente_id, s.lugar_id,
|
|
s.numero_orden,
|
|
s.total_cobrado, s.metodo_pago, s.observaciones, s.embarazada, s.solo_muestras, s.medico_id, s.creado_at,
|
|
l.nombre AS lugar_nombre,
|
|
CONCAT(m.nombres, ' ', m.apellidos) AS medico_nombre,
|
|
m.cod_especialidad AS medico_especialidad,
|
|
m.codigo AS medico_codigo
|
|
FROM turnero_solicitudes s
|
|
LEFT JOIN turnero_lugares l ON l.id = s.lugar_id
|
|
LEFT JOIN medicos m ON m.id = s.medico_id
|
|
WHERE s.turno_id = ?
|
|
LIMIT 1"
|
|
);
|
|
$stmt->execute([$turnoId]);
|
|
$solicitud = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
|
|
|
|
$paciente = null;
|
|
$examenes = [];
|
|
|
|
if ($solicitud) {
|
|
// Paciente
|
|
$stmt = $pdo->prepare(
|
|
"SELECT id, nombre_completo, tipo_documento, numero_documento,
|
|
fecha_nacimiento, telefono
|
|
FROM lab_pacientes
|
|
WHERE id = ?"
|
|
);
|
|
$stmt->execute([$solicitud['paciente_id']]);
|
|
$paciente = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
|
|
|
|
// Exámenes
|
|
$stmt = $pdo->prepare(
|
|
"SELECT et.id, et.codigo, et.nombre, et.categoria
|
|
FROM turnero_examen_items tei
|
|
JOIN exam_tipos et ON et.id = tei.exam_tipo_id
|
|
WHERE tei.solicitud_id = ?
|
|
ORDER BY et.categoria, et.nombre"
|
|
);
|
|
$stmt->execute([$solicitud['id']]);
|
|
$examenes = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Auto-crear consentimientos requeridos desde DOS fuentes:
|
|
// 1. Por examen → exam_tipo_consentimientos
|
|
// 2. Por lugar → turnero_lugar_consentimientos
|
|
$requeridos = [];
|
|
$vistosFIds = [];
|
|
|
|
// Fuente 1: examen
|
|
if (!empty($examenes)) {
|
|
$examIds = array_column($examenes, 'id');
|
|
$ph = implode(',', array_fill(0, count($examIds), '?'));
|
|
$stmtE = $pdo->prepare(
|
|
"SELECT DISTINCT etc.formulario_id, f.nombre AS formulario_nombre
|
|
FROM exam_tipo_consentimientos etc
|
|
JOIN lab_formularios f ON f.id = etc.formulario_id
|
|
WHERE etc.exam_tipo_id IN ($ph) AND f.is_active = 1"
|
|
);
|
|
$stmtE->execute($examIds);
|
|
foreach ($stmtE->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$fid = (int)$r['formulario_id'];
|
|
if (!in_array($fid, $vistosFIds, true)) {
|
|
$requeridos[] = $r;
|
|
$vistosFIds[] = $fid;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fuente 2: lugar destino ($lugarDestinoId y $fidsDeLugar ya calculados arriba)
|
|
if ($lugarDestinoId) {
|
|
$stmtL = $pdo->prepare(
|
|
"SELECT DISTINCT tlc.formulario_id, f.nombre AS formulario_nombre
|
|
FROM turnero_lugar_consentimientos tlc
|
|
JOIN lab_formularios f ON f.id = tlc.formulario_id
|
|
WHERE tlc.lugar_id = ? AND f.is_active = 1"
|
|
);
|
|
$stmtL->execute([$lugarDestinoId]);
|
|
foreach ($stmtL->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$fid = (int)$r['formulario_id'];
|
|
if (!in_array($fid, $vistosFIds, true)) {
|
|
$requeridos[] = $r;
|
|
$vistosFIds[] = $fid;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Auto-crear los registros que falten
|
|
if (!empty($requeridos)) {
|
|
$existFormIds = array_map('intval', array_column($consentimientos, 'formulario_id'));
|
|
$stmtIns = $pdo->prepare(
|
|
"INSERT IGNORE INTO turnero_consentimientos
|
|
(turno_id, formulario_id, token, estado)
|
|
VALUES (?, ?, ?, 'pendiente')"
|
|
);
|
|
$creados = 0;
|
|
foreach ($requeridos as $r) {
|
|
if (!in_array((int)$r['formulario_id'], $existFormIds, true)) {
|
|
$token = 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->execute([$turnoId, (int)$r['formulario_id'], $token]);
|
|
$creados++;
|
|
}
|
|
}
|
|
|
|
// Re-leer si se crearon nuevos registros y recalcular flags
|
|
if ($creados > 0) {
|
|
$stmtC = $pdo->prepare(
|
|
"SELECT tc.id, tc.turno_id, tc.formulario_id, tc.token,
|
|
tc.estado, tc.enviado_at, tc.firmado_at,
|
|
(tc.firma_profesional_svg IS NOT NULL) AS tiene_firma_profesional,
|
|
tc.firmado_profesional_at,
|
|
tc.siguiente_toma_at,
|
|
tc.toma_inicio_at,
|
|
tc.datos_respuestas,
|
|
f.nombre AS formulario_nombre,
|
|
f.esquema AS formulario_esquema
|
|
FROM turnero_consentimientos tc
|
|
LEFT JOIN lab_formularios f ON f.id = tc.formulario_id
|
|
WHERE tc.turno_id = ?
|
|
ORDER BY tc.id ASC"
|
|
);
|
|
$stmtC->execute([$turnoId]);
|
|
$consentimientos = $stmtC->fetchAll(PDO::FETCH_ASSOC);
|
|
foreach ($consentimientos as &$c) {
|
|
$esquema = $c['formulario_esquema'] ?? null;
|
|
$campos = [];
|
|
if ($esquema) {
|
|
$decoded = json_decode($esquema, true);
|
|
$campos = is_array($decoded) ? $decoded : ($decoded['campos'] ?? []);
|
|
}
|
|
$camposFirmaPro = array_values(array_filter($campos, fn($f) => ($f['tipo'] ?? '') === 'firma_profesional'));
|
|
$tieneFirmaPro = !empty($camposFirmaPro);
|
|
$tieneFirmaPac = !empty(array_filter($campos, fn($f) => ($f['tipo'] ?? '') === 'firma'));
|
|
$esTomaProg = count($camposFirmaPro) > 1;
|
|
$tomasFirm = 0;
|
|
if ($esTomaProg && $c['datos_respuestas']) {
|
|
$dr = json_decode($c['datos_respuestas'], true) ?? [];
|
|
foreach ($camposFirmaPro as $fp) {
|
|
if (!empty($dr[$fp['id']]) && strlen($dr[$fp['id']]) > 10) $tomasFirm++;
|
|
}
|
|
}
|
|
$c['requiere_firma_profesional'] = $tieneFirmaPro;
|
|
$c['requiere_firma_paciente'] = !($tieneFirmaPro && !$tieneFirmaPac);
|
|
$c['origen_lugar_id'] = in_array((int)$c['formulario_id'], $fidsDeLugar, true)
|
|
? $lugarDestinoId : null;
|
|
$c['es_toma_progresiva'] = $esTomaProg;
|
|
$c['tomas_total'] = count($camposFirmaPro);
|
|
$c['tomas_firmadas'] = $tomasFirm;
|
|
$c['campos_firma_pro'] = array_column($camposFirmaPro, 'id');
|
|
unset($c['formulario_esquema'], $c['datos_respuestas']);
|
|
}
|
|
unset($c);
|
|
$respuesta['consentimientos'] = $consentimientos;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Muestras pendientes / recibidas del turno
|
|
$muestras = [];
|
|
if ($solicitud) {
|
|
try {
|
|
$stmtM = $pdo->prepare(
|
|
"SELECT tm.id, tm.tipo_muestra, tm.estado, tm.motivo_rechazo, tm.recibida_at,
|
|
COALESCE(lt.nombre, tm.tipo_muestra) AS label
|
|
FROM turnero_muestras tm
|
|
LEFT JOIN lab_tipos_muestra lt ON lt.codigo = tm.tipo_muestra
|
|
WHERE tm.solicitud_id = ?
|
|
ORDER BY tm.id ASC"
|
|
);
|
|
$stmtM->execute([$solicitud['id']]);
|
|
$muestras = $stmtM->fetchAll(PDO::FETCH_ASSOC);
|
|
} catch (\Throwable $_) {
|
|
// Tabla aún no existe
|
|
}
|
|
}
|
|
|
|
$respuesta['solicitud'] = $solicitud;
|
|
$respuesta['paciente'] = $paciente;
|
|
$respuesta['examenes'] = $examenes;
|
|
$respuesta['muestras'] = $muestras;
|
|
}
|
|
|
|
jsonOk($respuesta);
|