# Módulo Turnero El módulo más grande del sistema: 12 vistas y unos 70 endpoints. Gestiona la atención presencial completa. ## Vistas | Vista | Para quién | Qué hace | |---|---|---| | `dashboard` | Admin, supervisor | Métricas del día, facturación, asistente LIA | | `historial` | Admin, supervisor | Turnos de varios días, filtros, exportación | | `bandeja` | Bacteriólogo, admin | Turnos del día con su detalle completo | | `recepcion` | Recepcionista | Atención en el mostrador | | `lugar` | Bacteriólogo | Estación de toma de muestras | | `kiosko` | Público | El paciente saca su turno | | `display_global` | Público | Pantalla de TV de la sala | | `verificar_paciente` | Recepción | Consulta rápida de una ficha | | `chat` | Recepción | Conversación de WhatsApp del turnero | | `configuracion` | Admin | Lugares, dispositivos, plantillas, pantalla de TV | `kiosko` y `display_global` son las **únicas rutas públicas** del sistema (`core/Router.php`): no hay quién inicie sesión en un televisor ni en el tótem de la entrada. ## Menú dinámico `modules/turnero/module.php` no devuelve una lista fija: la arma según **el rol y la IP del equipo**. ``` recepcionista → chat, verificar paciente, TV, y su escritorio bacteriólogo → bandeja y su estación admin → todo ``` Si el equipo está en `turnero_dispositivos` (por IP o por cookie `turnero_token`), el usuario ve **solo su puesto**. Si no, los ve todos. Evita que alguien atienda desde el escritorio equivocado. ## Modelo de datos ``` turnero_sesiones un día de operación └── turnero_turnos código, estado, tiempos, prioridad ├── turnero_solicitudes qué se hace y cuánto se cobró │ ├── turnero_examen_items │ └── turnero_muestras ├── turnero_consentimientos └── turnero_comentarios ``` ### Estados ``` espera → en_recepcion → en_espera_lugar → en_servicio → finalizado ausente / cancelado ``` Solo `finalizado` cuenta como facturación real. ## Consentimientos Se crean automáticamente desde **dos fuentes** que se acumulan: | Fuente | Tabla | |---|---| | Por examen | `exam_tipo_consentimientos` | | Por estación destino | `turnero_lugar_consentimientos` | `get_consentimientos.php` los autocrea si faltan y calcula el estado de cada uno. > En visitas de *solo entrega de muestras* no aplican los formularios por examen (no hay exámenes), pero **sí los de estación**. Por eso F-LAB-08 se exige igual. ## Tomas prolongadas El formulario **F-LAB-28** cubre exámenes seriados. La lógica está repartida entre `ver_formulario_enviado.php` (render) y `modules/turnero/api/guardar_toma.php` (guardado). - El esquema trae secciones para todos los exámenes posibles; se muestran solo las del examen marcado, mediante la `condicion` de cada separador. - `_tomas_config` en `datos_respuestas` guarda qué ciclos se configuraron para ese paciente. - Cada firma se guarda en su propio campo (`_tm00_f`, `_tm30_f`, …) junto con la hora y **la identidad de quien firmó**, resuelta en el servidor desde la sesión. - Al firmar, el endpoint calcula cuándo toca la siguiente toma y actualiza `siguiente_toma_at`. > La identidad se resuelve **en el servidor**, no se acepta del cliente: cada toma puede firmarla un profesional distinto y esa es la única fuente confiable. Las firmas anteriores al 3 de agosto de 2026 no tienen ese dato y no es recuperable. ## Muestras entre visitas Una muestra que queda `pendiente` o `rechazada` reaparece cuando el paciente vuelve, con la bandera `es_pendiente_anterior` y los exámenes de la orden original. Al recibirla, `turnero_muestras.recibida_en_turno_id` registra en qué turno se completó. Historial y bandeja usan ese dato para enlazar ambos turnos en los dos sentidos. **El turno original no se modifica**: sigue finalizado. Solo se agrega la trazabilidad. ## LIA `api/ai_chat.php` — asistente sobre Gemini Flash. | Aspecto | Detalle | |---|---| | Contexto | Se arma en cada llamada con hasta 60 turnos del día y sus detalles | | Historial | Los últimos intercambios se envían para que entienda preguntas de seguimiento | | Tope de salida | `maxOutputTokens`; si Gemini corta, se avisa con `finishReason` | | Presupuesto | `lab_config.lia_tokens_usados` contra `LIA_TOKENS_MAX` | Se contabiliza `totalTokenCount`, que **incluye el contexto de entrada**. Como el contexto va completo en cada pregunta, el gasto por consulta es alto aunque la respuesta sea breve. ## Endpoints propios Los del turnero usan `api/_helpers.php`, que provee `db()`, `inputJson()`, `jsonOk()`, `jsonError()`, `adminId()`, `requireTurnero()` y `notificarSSE()`. `notificarSSE()` avisa a las pantallas conectadas para que se refresquen sin recargar.