query( "SELECT id FROM turnero_sesiones ORDER BY id DESC LIMIT 1" )->fetchColumn() ?: 0); // ── DETALLE ─────────────────────────────────────────────────── if (isset($_GET['turno_id'])) { $tid = (int)$_GET['turno_id']; $turno = $pdo->prepare(" SELECT t.id, t.codigo, t.estado, t.paciente_nombre, t.inicio_lugar_at, t.fin_lugar_at, t.bandeja_visto_at, ts.id AS sol_id, ts.numero_orden, p.tipo_documento, p.numero_documento, p.fecha_nacimiento, p.telefono, l.nombre AS lugar_nombre FROM turnero_turnos t JOIN turnero_solicitudes ts ON ts.turno_id = t.id LEFT JOIN lab_pacientes p ON p.id = ts.paciente_id LEFT JOIN turnero_lugares l ON l.id = t.lugar_destino_id WHERE t.id = ? LIMIT 1 "); $turno->execute([$tid]); $data = $turno->fetch(PDO::FETCH_ASSOC); if (!$data) jsonError('Turno no encontrado', 404); $solId = (int)$data['sol_id']; // Exámenes agrupados por categoría $stmtEx = $pdo->prepare(" SELECT et.codigo, et.nombre, COALESCE(NULLIF(et.categoria,''),'Otros') AS categoria FROM turnero_examen_items tei JOIN exam_tipos et ON et.id = tei.exam_tipo_id WHERE tei.solicitud_id = ? ORDER BY categoria, et.nombre "); $stmtEx->execute([$solId]); $examenesPorCat = []; foreach ($stmtEx->fetchAll(PDO::FETCH_ASSOC) as $e) { $examenesPorCat[$e['categoria']][] = $e['codigo']; } // Muestras $stmtM = $pdo->prepare(" SELECT tm.id, tm.tipo_muestra, tm.estado, tm.motivo_rechazo, tm.recibida_at FROM turnero_muestras tm WHERE tm.solicitud_id = ? ORDER BY tm.id "); $stmtM->execute([$solId]); $muestras = $stmtM->fetchAll(PDO::FETCH_ASSOC); // Consentimientos $stmtC = $pdo->prepare(" SELECT tc.id, tc.estado, tc.token, tc.firmado_at, lf.nombre AS formulario_nombre FROM turnero_consentimientos tc JOIN lab_formularios lf ON lf.id = tc.formulario_id WHERE tc.turno_id = ? ORDER BY tc.id "); $stmtC->execute([$tid]); $consentimientos = $stmtC->fetchAll(PDO::FETCH_ASSOC); // Comentarios (todos los tipos) $stmtCom = $pdo->prepare(" SELECT tipo, usuario_nombre, comentario, creado_at FROM turnero_comentarios WHERE turno_id = ? ORDER BY creado_at ASC "); $stmtCom->execute([$tid]); $comentarios = $stmtCom->fetchAll(PDO::FETCH_ASSOC); // Turnos vinculados por muestras pendientes completadas en otra visita (ambos sentidos) $relacionados = []; $stmtRelFwd = $pdo->prepare(" SELECT t2.id AS rel_id, t2.codigo AS rel_codigo, s2.fecha AS rel_fecha FROM turnero_muestras tm JOIN turnero_turnos t2 ON t2.id = tm.recibida_en_turno_id JOIN turnero_sesiones s2 ON s2.id = t2.sesion_id WHERE tm.solicitud_id = ? AND tm.recibida_en_turno_id IS NOT NULL "); $stmtRelFwd->execute([$solId]); foreach ($stmtRelFwd->fetchAll(PDO::FETCH_ASSOC) as $r) { $relacionados[] = ['turno_id' => (int)$r['rel_id'], 'codigo' => $r['rel_codigo'], 'fecha' => $r['rel_fecha'], 'direccion' => 'seguimiento']; } $stmtRelBack = $pdo->prepare(" SELECT t1.id AS rel_id, t1.codigo AS rel_codigo, s1.fecha AS rel_fecha FROM turnero_muestras tm JOIN turnero_solicitudes ts1 ON ts1.id = tm.solicitud_id JOIN turnero_turnos t1 ON t1.id = ts1.turno_id JOIN turnero_sesiones s1 ON s1.id = t1.sesion_id WHERE tm.recibida_en_turno_id = ? "); $stmtRelBack->execute([$tid]); foreach ($stmtRelBack->fetchAll(PDO::FETCH_ASSOC) as $r) { $relacionados[] = ['turno_id' => (int)$r['rel_id'], 'codigo' => $r['rel_codigo'], 'fecha' => $r['rel_fecha'], 'direccion' => 'origen']; } jsonOk([ 'turno' => $data, 'examenes_por_cat'=> $examenesPorCat, 'muestras' => $muestras, 'consentimientos' => $consentimientos, 'comentarios' => $comentarios, 'relacionados' => $relacionados, ]); } // ── LISTA ───────────────────────────────────────────────────── $desde = $_GET['desde'] ?? null; $hasta = $_GET['hasta'] ?? null; if ($desde && $hasta) { $whereClause = "DATE(t.inicio_lugar_at) BETWEEN ? AND ?"; $params = [$desde, $hasta]; } else { $whereClause = "t.sesion_id = ?"; $params = [$sesionId]; } $stmt = $pdo->prepare(" SELECT t.id, t.codigo, t.paciente_nombre, t.estado, t.inicio_lugar_at, t.fin_lugar_at, t.bandeja_visto_at, t.muestra_espera_at, ts.numero_orden, l.nombre AS lugar_nombre, GROUP_CONCAT(DISTINCT et.codigo ORDER BY et.codigo SEPARATOR ' ') AS examenes_txt, SUM(tc.tipo = 'recepcion') AS com_recepcion, SUM(tc.tipo = 'muestras') AS com_muestras, SUM(tc.tipo = 'general') AS com_general, (SELECT COUNT(*) FROM turnero_muestras tm2 WHERE tm2.solicitud_id = ts.id AND tm2.estado = 'rechazada') AS muestras_pendientes FROM turnero_turnos t JOIN turnero_solicitudes ts ON ts.turno_id = t.id JOIN turnero_lugares l ON l.id = t.lugar_destino_id LEFT JOIN turnero_examen_items tei ON tei.solicitud_id = ts.id LEFT JOIN exam_tipos et ON et.id = tei.exam_tipo_id LEFT JOIN turnero_comentarios tc ON tc.turno_id = t.id WHERE $whereClause AND t.inicio_lugar_at IS NOT NULL GROUP BY t.id ORDER BY ts.numero_orden ASC "); $stmt->execute($params); $todos = $stmt->fetchAll(PDO::FETCH_ASSOC); $pendientes = array_values(array_filter($todos, fn($t) => $t['bandeja_visto_at'] === null)); $vistos = array_values(array_filter($todos, fn($t) => $t['bandeja_visto_at'] !== null)); $muestrasPendientes = count(array_filter($todos, fn($t) => (int)$t['muestras_pendientes'] > 0)); $prolongadasPendientes = count(array_filter($todos, fn($t) => !empty($t['muestra_espera_at']) && empty($t['fin_lugar_at']))); jsonOk([ 'pendientes' => $pendientes, 'vistos' => $vistos, 'stats' => [ 'total' => count($todos), 'pendientes' => count($pendientes), 'vistos' => count($vistos), 'muestras_pendientes' => $muestrasPendientes, 'prolongadas_pendientes'=> $prolongadasPendientes, ], ]);