- 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 <noreply@anthropic.com>
473 lines
23 KiB
PHP
473 lines
23 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, paciente_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 ──────────────────────────────────────────────────────
|
|
// Solo cuando el turno tiene lugar destino asignado. En recepción (NULL),
|
|
// fidsDeLugar queda vacío → todos los consentimientos reciben origen_lugar_id=null
|
|
// → pasan el filtro !c.origen_lugar_id de recepcion.php.
|
|
$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));
|
|
}
|
|
|
|
// ── 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,
|
|
f.es_toma_progresiva AS formulario_es_toma_prog,
|
|
f.solo_profesional AS formulario_solo_profesional
|
|
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: 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) {
|
|
|
|
// Mapear cada firma_profesional a los valores de examen de su sección condicional
|
|
$firmaCondMap = [];
|
|
$curCondCampo = null;
|
|
$curCondVals = [];
|
|
foreach ($campos as $campo) {
|
|
$ft = $campo['tipo'] ?? '';
|
|
if ($ft === 'separador') {
|
|
$cond = $campo['condicion'] ?? null;
|
|
$curCondCampo = $cond ? ($cond['campo_id'] ?? null) : null;
|
|
$curCondVals = $cond
|
|
? ($cond['valores'] ?? ($cond['valor'] ? [$cond['valor']] : []))
|
|
: [];
|
|
} elseif ($ft === 'firma_profesional' && !empty($campo['id'])) {
|
|
$firmaCondMap[$campo['id']] = ['campo' => $curCondCampo, 'valores' => $curCondVals];
|
|
}
|
|
}
|
|
|
|
// Filtrar por exámenes seleccionados en datos_respuestas
|
|
$relevantIds = [];
|
|
foreach ($firmaCondMap as $fid => $info) {
|
|
if ($info['campo'] === null) {
|
|
$relevantIds[] = $fid; // sin condición → siempre aplica
|
|
} else {
|
|
$ctrlVal = $dr[$info['campo']] ?? null;
|
|
$ctrlArr = is_array($ctrlVal) ? $ctrlVal : ($ctrlVal !== null ? [$ctrlVal] : []);
|
|
if (!empty(array_intersect($info['valores'], $ctrlArr))) {
|
|
$relevantIds[] = $fid;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Si hay config de tomas guardada, restringir al subconjunto seleccionado
|
|
$tomasConfig = is_array($dr['_tomas_config'] ?? null) ? $dr['_tomas_config'] : null;
|
|
if ($tomasConfig !== null) {
|
|
$allowedFids = [];
|
|
foreach ($tomasConfig as $__v) {
|
|
if (!is_array($__v)) continue;
|
|
$__inner = reset($__v);
|
|
// nested: exam => { group => [fids] }; flat: group => [fids]
|
|
if (is_array($__inner)) { foreach ($__v as $__fids) foreach ($__fids as $__f) $allowedFids[] = $__f; }
|
|
else { foreach ($__v as $__f) $allowedFids[] = $__f; }
|
|
}
|
|
$allowedFids = array_unique($allowedFids);
|
|
$relevantIds = array_values(array_filter($relevantIds, fn($id) => in_array($id, $allowedFids, true)));
|
|
}
|
|
|
|
$tomasTotal = count($relevantIds);
|
|
foreach ($relevantIds as $fid) {
|
|
if ((!empty($dr[$fid]) && strlen($dr[$fid]) > 10)
|
|
|| (!empty($dr[$fid.'_svg']) && strlen($dr[$fid.'_svg']) > 10)) $tomasFirm++;
|
|
}
|
|
}
|
|
|
|
$soloPro = !empty($c['formulario_solo_profesional']);
|
|
$c['requiere_firma_profesional'] = $tieneFirmaPro;
|
|
$c['requiere_firma_paciente'] = $soloPro ? false : !($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;
|
|
$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']);
|
|
}
|
|
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);
|
|
|
|
// Visita de solo entrega de muestras: no requiere consentimientos ni formularios
|
|
if (!empty($solicitud['solo_muestras'])) {
|
|
$respuesta['consentimientos'] = [];
|
|
$respuesta['solicitud'] = $solicitud;
|
|
$respuesta['paciente'] = $paciente;
|
|
$respuesta['examenes'] = $examenes;
|
|
// Muestras pendientes de visitas anteriores
|
|
$muestras = [];
|
|
try {
|
|
$stmtPrev = $pdo->prepare(
|
|
"SELECT tm.id, tm.tipo_muestra, tm.estado, tm.motivo_rechazo, tm.recibida_at,
|
|
COALESCE(lt.nombre, tm.tipo_muestra) AS label,
|
|
1 AS es_pendiente_anterior,
|
|
ts.numero_orden AS solicitud_orden_anterior
|
|
FROM turnero_muestras tm
|
|
JOIN turnero_solicitudes ts ON ts.id = tm.solicitud_id
|
|
LEFT JOIN lab_tipos_muestra lt ON lt.codigo = tm.tipo_muestra
|
|
WHERE ts.paciente_id = ?
|
|
AND tm.solicitud_id != ?
|
|
AND tm.estado = 'pendiente'
|
|
ORDER BY tm.id ASC"
|
|
);
|
|
$stmtPrev->execute([$solicitud['paciente_id'], $solicitud['id']]);
|
|
$muestras = $stmtPrev->fetchAll(PDO::FETCH_ASSOC);
|
|
} catch (\Throwable $_) {}
|
|
$respuesta['muestras'] = $muestras;
|
|
jsonOk($respuesta);
|
|
}
|
|
|
|
// 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,
|
|
f.es_toma_progresiva AS formulario_es_toma_prog,
|
|
f.solo_profesional AS formulario_solo_profesional
|
|
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'));
|
|
$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) {
|
|
$firmaCondMap2 = [];
|
|
$curC2 = null; $curV2 = [];
|
|
foreach ($campos as $campo2) {
|
|
$ft2 = $campo2['tipo'] ?? '';
|
|
if ($ft2 === 'separador') {
|
|
$cond2 = $campo2['condicion'] ?? null;
|
|
$curC2 = $cond2 ? ($cond2['campo_id'] ?? null) : null;
|
|
$curV2 = $cond2 ? ($cond2['valores'] ?? ($cond2['valor'] ? [$cond2['valor']] : [])) : [];
|
|
} elseif ($ft2 === 'firma_profesional' && !empty($campo2['id'])) {
|
|
$firmaCondMap2[$campo2['id']] = ['campo' => $curC2, 'valores' => $curV2];
|
|
}
|
|
}
|
|
$relevantIds2 = [];
|
|
foreach ($firmaCondMap2 as $fid2 => $info2) {
|
|
if ($info2['campo'] === null) {
|
|
$relevantIds2[] = $fid2;
|
|
} else {
|
|
$cv2 = $dr2[$info2['campo']] ?? null;
|
|
$ca2 = is_array($cv2) ? $cv2 : ($cv2 !== null ? [$cv2] : []);
|
|
if (!empty(array_intersect($info2['valores'], $ca2))) $relevantIds2[] = $fid2;
|
|
}
|
|
}
|
|
$cfg2 = is_array($dr2['_tomas_config'] ?? null) ? $dr2['_tomas_config'] : null;
|
|
if ($cfg2 !== null) {
|
|
$allowed2 = [];
|
|
foreach ($cfg2 as $__v2) {
|
|
if (!is_array($__v2)) continue;
|
|
$__i2 = reset($__v2);
|
|
if (is_array($__i2)) { foreach ($__v2 as $__fids2) foreach ($__fids2 as $__f2) $allowed2[] = $__f2; }
|
|
else { foreach ($__v2 as $__f2) $allowed2[] = $__f2; }
|
|
}
|
|
$allowed2 = array_unique($allowed2);
|
|
$relevantIds2 = array_values(array_filter($relevantIds2, fn($id) => in_array($id, $allowed2, true)));
|
|
}
|
|
$tomasTotal2 = count($relevantIds2);
|
|
foreach ($relevantIds2 as $fid2) {
|
|
if (!empty($dr2[$fid2]) && strlen($dr2[$fid2]) > 10) $tomasFirm++;
|
|
}
|
|
}
|
|
$soloPro2 = !empty($c['formulario_solo_profesional']);
|
|
$c['requiere_firma_profesional'] = $tieneFirmaPro;
|
|
$c['requiere_firma_paciente'] = $soloPro2 ? false : !($tieneFirmaPro && !$tieneFirmaPac);
|
|
$c['origen_lugar_id'] = in_array((int)$c['formulario_id'], $fidsDeLugar, true)
|
|
? $lugarDestinoId : null;
|
|
$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']);
|
|
}
|
|
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,
|
|
0 AS es_pendiente_anterior, NULL AS solicitud_orden_anterior
|
|
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);
|
|
|
|
// Si es visita de entrega de muestras, agregar pendientes de solicitudes anteriores
|
|
if (!empty($solicitud['solo_muestras']) && !empty($solicitud['paciente_id'])) {
|
|
$stmtPrev = $pdo->prepare(
|
|
"SELECT tm.id, tm.tipo_muestra, tm.estado, tm.motivo_rechazo, tm.recibida_at,
|
|
COALESCE(lt.nombre, tm.tipo_muestra) AS label,
|
|
1 AS es_pendiente_anterior,
|
|
ts.numero_orden AS solicitud_orden_anterior
|
|
FROM turnero_muestras tm
|
|
JOIN turnero_solicitudes ts ON ts.id = tm.solicitud_id
|
|
LEFT JOIN lab_tipos_muestra lt ON lt.codigo = tm.tipo_muestra
|
|
WHERE ts.paciente_id = ?
|
|
AND tm.solicitud_id != ?
|
|
AND tm.estado = 'pendiente'
|
|
ORDER BY tm.id ASC"
|
|
);
|
|
$stmtPrev->execute([$solicitud['paciente_id'], $solicitud['id']]);
|
|
$previas = $stmtPrev->fetchAll(PDO::FETCH_ASSOC);
|
|
$muestras = array_merge($previas, $muestras);
|
|
}
|
|
} catch (\Throwable $_) {
|
|
// Tabla aún no existe
|
|
}
|
|
}
|
|
|
|
// Fallback: sin solicitud pero el turno tiene paciente_id → buscar muestras pendientes igualmente
|
|
if (!$solicitud && !empty($turno['paciente_id'])) {
|
|
$pacId = (int)$turno['paciente_id'];
|
|
$stmt = $pdo->prepare(
|
|
"SELECT id, nombre_completo, tipo_documento, numero_documento,
|
|
fecha_nacimiento, telefono
|
|
FROM lab_pacientes WHERE id = ?"
|
|
);
|
|
$stmt->execute([$pacId]);
|
|
$paciente = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
|
|
try {
|
|
$stmtPrev = $pdo->prepare(
|
|
"SELECT tm.id, tm.tipo_muestra, tm.estado, tm.motivo_rechazo, tm.recibida_at,
|
|
COALESCE(lt.nombre, tm.tipo_muestra) AS label,
|
|
1 AS es_pendiente_anterior,
|
|
ts.numero_orden AS solicitud_orden_anterior
|
|
FROM turnero_muestras tm
|
|
JOIN turnero_solicitudes ts ON ts.id = tm.solicitud_id
|
|
LEFT JOIN lab_tipos_muestra lt ON lt.codigo = tm.tipo_muestra
|
|
WHERE ts.paciente_id = ?
|
|
AND tm.estado = 'pendiente'
|
|
ORDER BY tm.id ASC"
|
|
);
|
|
$stmtPrev->execute([$pacId]);
|
|
$muestras = $stmtPrev->fetchAll(PDO::FETCH_ASSOC);
|
|
} catch (\Throwable $_) {}
|
|
}
|
|
|
|
$respuesta['solicitud'] = $solicitud;
|
|
$respuesta['paciente'] = $paciente;
|
|
$respuesta['examenes'] = $examenes;
|
|
$respuesta['muestras'] = $muestras;
|
|
}
|
|
|
|
jsonOk($respuesta);
|