25 KiB
Documentación del Sistema de Laboratorio
Sistema: Laboratorio Clínico — Módulos de Agendamiento y Formularios
Última actualización: 27/03/2026
Tabla de contenidos
1. Módulo de Agendamiento (Domicilios)
¿Qué es?
El módulo de agendamiento gestiona los servicios de toma de muestras a domicilio. Permite crear, asignar, seguir y completar visitas médicas domiciliarias. Los administradores gestionan la agenda desde lab_domicilios.php; los enfermeros gestionan su propia agenda desde enfermero_portal.php.
Archivos involucrados
| Archivo | Descripción |
|---|---|
lab_domicilios.php |
Vista principal del admin — tabla con filtros, detalle del domicilio, formularios recibidos, exportar CSV |
enfermero_portal.php |
Portal exclusivo del enfermero — su agenda personal del día, ordenada por hora, con tarjetas colapsables |
lab_enfermeras.php |
CRUD del personal de enfermería |
classes/lab/Domicilio.php |
Clase ORM — crear, editar, cambiar estado, estadísticas |
classes/lab/Enfermera.php |
Clase ORM — CRUD, agenda por enfermero, carga de trabajo |
classes/lab/Asignacion.php |
Clase ORM — asignar / reasignar / liberar enfermero a domicilio |
api/lab/get_domicilios.php |
GET — lista de domicilios con filtros y estadísticas del día |
api/lab/save_domicilio.php |
POST — crear, actualizar o cambiar estado |
api/lab/update_domicilio_enfermero.php |
POST — el enfermero avanza el estado desde su portal |
api/lab/my_agenda.php |
GET — agenda del enfermero actualmente autenticado |
api/lab/save_asignacion.php |
POST — asignar o reasignar enfermero |
api/lab/get_asignaciones.php |
GET — asignaciones por fecha |
api/lab/registrar_pago.php |
POST — registrar pago de un domicilio |
api/lab/save_servicio_extra.php |
POST — agregar servicio realizado durante la visita |
api/lab/get_notas_domicilio.php |
GET — notas clínicas y libres del domicilio |
api/lab/upload_nota_imagen.php |
POST — subir imagen adjunta a una nota |
api/lab/crear_desde_whatsapp.php |
GET/POST — crear paciente u orden desde una conversación de WhatsApp activa |
Base de datos
Tabla lab_domicilios
Tabla principal. Cada fila es un servicio a domicilio.
| Campo | Tipo | Descripción |
|---|---|---|
id |
INT PK | Identificador único |
paciente_id |
INT FK | Paciente al que se le realiza el servicio |
orden_id |
INT FK NULL | Orden médica adjunta (opcional) |
direccion |
TEXT | Dirección completa de la visita |
ciudad |
VARCHAR(100) | Ciudad |
barrio |
VARCHAR(100) | Barrio |
indicaciones_dir |
TEXT | Referencias o indicaciones adicionales ("apto 302, tocar campanilla") |
fecha_programada |
DATE | Fecha de la visita |
hora_programada |
TIME | Hora de la visita |
tipo_servicio |
VARCHAR(100) | Tipo de servicio (toma de muestra, etc.) |
tipo_cliente |
ENUM | particular / seguro / eps |
examenes_solicitados |
TEXT | Lista de exámenes (cuando no hay orden médica) |
seguro_nombre |
VARCHAR | Nombre del seguro o EPS |
autorizacion |
VARCHAR | Número de autorización |
valor_domicilio |
DECIMAL | Valor del servicio |
valor_copago |
DECIMAL | Copago a cargo del cliente |
copago_laboratorio |
DECIMAL | Copago al laboratorio |
pago_estado |
ENUM | pending / pagado / exento |
pago_modo |
ENUM | efectivo / transferencia / otro |
pago_monto |
DECIMAL | Monto pagado |
pago_fecha |
DATETIME | Fecha del pago |
pago_notas |
TEXT | Notas sobre el pago |
estado |
ENUM | Ver Flujo de estados |
motivo_cancelacion |
TEXT | Motivo si fue cancelado (obligatorio) |
fecha_reprogramada |
DATE | Nueva fecha si fue reprogramado |
hora_llegada |
TIME | Registrada automáticamente al iniciar la visita |
hora_salida |
TIME | Registrada automáticamente al completar |
observaciones |
TEXT | Observaciones del resultado de la visita |
muestras_tomadas |
TEXT | Lista de muestras obtenidas |
notas_admin |
TEXT | Notas internas del equipo administrativo |
creado_por |
INT FK | Usuario que creó el registro |
Tabla lab_enfermeras
Personal de enfermería disponible para asignación.
Campos: id, numero_documento, tipo_documento (CC/CE/TI/PA), nombre_completo, telefono, telefono_alt, email, zona, notas, is_active.
Tabla lab_asignaciones
Asignación de enfermero a domicilio. Máximo un enfermero activo por domicilio (UNIQUE KEY en domicilio_id).
Campos: id, domicilio_id, enfermera_id, asignada_por, estado (asignada / confirmada / liberada / completada), notas.
Tabla lab_servicios_extra
Servicios realizados por el enfermero durante la visita, adicionales a la orden original.
Tipos disponibles: inyeccion, cura, nebulizacion, toma_muestra, tension_arterial, glucometria, otro.
Campos: id, domicilio_id, descripcion, tipo, notas, requiere_pago, valor, realizado_por.
Tabla lab_domicilio_notas
Notas registradas por el enfermero durante la visita.
Dos tipos:
clinica: datos de la ficha clínica — antecedentes, medicamentos, acudiente (si el paciente es menor de edad).libre: nota libre con título, cuerpo de texto enriquecido e imagen adjunta.
Campos: id, domicilio_id, enfermera_id, tipo, antecedentes, medicamentos, acudiente_nombre, acudiente_documento, titulo, cuerpo, imagen_path.
Roles y permisos
| Rol | Acceso |
|---|---|
| Admin | Crear, editar y ver todos los domicilios. Asignar/reasignar enfermeros. Registrar pagos. Exportar Excel. Ver informe completo con notas. Ver agenda de cualquier enfermero usando ?eid=X. |
| Enfermero | Solo ve su propia agenda (enfermero_portal.php). Avanza el estado de sus domicilios asignados. Agrega servicios extra. Registra notas clínicas y libres. Visualiza órdenes médicas adjuntas. |
Redirección automática: si el usuario autenticado tiene rol
enfermero,lab_domicilios.phplo redirige inmediatamente aenfermero_portal.php.
Los roles se definen en admin_users.role (ENUM admin / enfermero) y admin_users.enfermera_id (FK a lab_enfermeras).
Flujo de estados
[programado]
│
│ El enfermero confirma que realizará la visita
▼
[confirmado]
│
│ El enfermero sale hacia el domicilio
▼
[en_camino]
│
│ El enfermero llega → hora_llegada se registra automáticamente
▼
[en_domicilio]
│
│ El enfermero finaliza → hora_salida se registra automáticamente
▼
[completado]
Desde cualquier estado:
→ [cancelado] (requiere motivo_cancelacion como campo obligatorio)
→ [reprogramado] (requiere fecha_reprogramada)
Transiciones permitidas al enfermero (validadas en update_domicilio_enfermero.php):
| Estado actual | Estados posibles |
|---|---|
programado |
confirmado |
confirmado |
en_camino, cancelado |
en_camino |
en_domicilio, cancelado |
en_domicilio |
completado, cancelado |
El admin puede cambiar a cualquier estado directamente, incluyendo cancelar desde cualquier punto.
Funcionalidades
- Filtros: por fecha, estado, enfermero asignado. Botón "Hoy" para filtro rápido.
- Resumen del día: conteo de domicilios por estado en la parte superior.
- Panel de detalle: al hacer clic en un domicilio se abre el panel lateral con toda la información, notas clínicas, notas libres e informe imprimible.
- Asignar / Reasignar enfermero: modal con lista del personal disponible.
- Sin asignar: badge con el conteo de domicilios que aún no tienen enfermero.
- Registrar pago: modal para marcar el cobro con modalidad y monto.
- Servicios extra: el enfermero los agrega desde su portal durante la visita.
- Notas del enfermero: ficha clínica con antecedentes, medicamentos, acudiente (si menor) y notas libres con imagen adjunta.
- Informe de domicilio: vista imprimible del domicilio con datos del paciente, ficha clínica y notas del enfermero.
- Exportar CSV (Excel): exporta todos los domicilios filtrados, incluyendo las columnas de notas del enfermero (antecedentes, medicamentos, acudiente, notas libres).
- Formularios recibidos: pestaña dentro de
lab_domicilios.phpque muestra formularios enviados con filtro por plantilla y estado. - Portal del enfermero: tarjetas colapsables ordenadas por hora, separadas en "Activos" y "Finalizados". Permite avanzar estados, agregar notas y ver órdenes.
API Endpoints
| Endpoint | Método | Descripción |
|---|---|---|
api/lab/get_domicilios.php |
GET | Lista con filtros. ?id=X para uno solo con detalle completo. |
api/lab/save_domicilio.php |
POST | Crear, editar o cambiar estado. ?solo_estado=true para solo cambiar estado. |
api/lab/update_domicilio_enfermero.php |
POST | El enfermero avanza el estado de su domicilio. |
api/lab/my_agenda.php |
GET | Agenda del enfermero autenticado con servicios extra. |
api/lab/save_asignacion.php |
POST | Asignar o reasignar enfermero a domicilio. |
api/lab/get_asignaciones.php |
GET | Asignaciones por fecha. |
api/lab/registrar_pago.php |
POST | Registrar pago con monto y modalidad. |
api/lab/save_servicio_extra.php |
POST | Agregar servicio realizado durante la visita. |
api/lab/get_notas_domicilio.php |
GET | Notas del domicilio (clínicas y libres). |
api/lab/upload_nota_imagen.php |
POST | Subir imagen adjunta a una nota libre. |
api/lab/crear_desde_whatsapp.php |
GET/POST | Crear paciente u orden desde una conversación de WhatsApp activa. |
2. Módulo de Formularios
¿Qué es?
El módulo de formularios permite crear plantillas de documentos (consentimientos, historias clínicas, autorizaciones, encuestas) mediante un builder visual, enviarlas a los pacientes por WhatsApp y recopilar sus respuestas con firma digital. El documento firmado genera un sello de integridad SHA-256 que puede verificarse públicamente.
Archivos involucrados
| Archivo | Descripción |
|---|---|
lab_formularios.php |
Vista principal — lista de plantillas y registro de envíos |
lab_formulario_builder.php |
Editor visual drag & drop (ventana separada, solo admin) |
form_cliente.php |
Página pública — el paciente llena y firma sin iniciar sesión |
ver_formulario_enviado.php |
Vista del documento firmado — acceso por ID (admin/enfermero) o token (cliente) |
verificar_formulario.php |
Verificación pública de autenticidad por hash SHA-256 |
classes/lab/Formulario.php |
Clase ORM — CRUD de plantillas, crear envíos, guardar respuestas, generar hash |
api/lab/get_formularios.php |
GET — lista plantillas o envíos |
api/lab/save_formulario.php |
POST — crear, editar y eliminar plantillas (solo admin) |
api/lab/send_formulario.php |
POST — crear instancia de envío, devolver URL pública y mensaje WhatsApp |
api/lab/submit_formulario.php |
GET/POST — cargar el formulario por token / guardar la respuesta del cliente |
api/lab/firmar_profesional.php |
POST — guardar firma del profesional (requiere sesión activa) |
Base de datos
Tabla lab_formularios
Plantillas de documentos creadas desde el builder.
| Campo | Tipo | Descripción |
|---|---|---|
id |
INT PK | Identificador único |
nombre |
VARCHAR(150) | Nombre de la plantilla |
descripcion |
TEXT | Descripción visible al cliente |
categoria |
ENUM | consentimiento / historia_clinica / autorizacion / encuesta / otro |
esquema |
LONGTEXT | JSON con el array de campos del formulario |
permite_firma |
TINYINT(1) | El formulario tiene sección de firma global |
requiere_firma |
TINYINT(1) | La firma global es obligatoria |
firma_modos |
VARCHAR(50) | canvas, foto o canvas,foto (separados por coma) |
version |
SMALLINT | Se incrementa automáticamente al editar el esquema |
is_active |
TINYINT(1) | Soft-delete |
creado_por |
INT FK | Usuario que creó la plantilla |
doc_encabezado |
VARCHAR | Override del nombre de empresa en el documento |
doc_subtitulo |
VARCHAR | Override del subtítulo en el documento |
doc_logo_base64 |
LONGTEXT | Override del logo en el documento |
doc_color |
VARCHAR(20) | Override del color del encabezado del documento |
doc_pie_pagina |
TEXT | Override del pie de página |
Tabla lab_form_envios
Cada fila es una instancia enviada a un paciente.
| Campo | Tipo | Descripción |
|---|---|---|
id |
INT PK | Identificador único |
formulario_id |
INT FK | Plantilla enviada |
paciente_id |
INT FK NULL | Paciente asociado |
domicilio_id |
INT FK NULL | Domicilio asociado (opcional) |
token |
CHAR(64) UNIQUE | Token público de 64 caracteres hex (acceso sin sesión) |
datos_prefilled |
LONGTEXT | JSON con datos pre-llenados al enviar (incluye __paciente.*) |
datos_cliente |
LONGTEXT | JSON con las respuestas completadas por el cliente |
firma_svg |
LONGTEXT | Firma del paciente (PNG base64 — canvas o foto) |
ip_cliente |
VARCHAR(45) | IP del cliente al enviar el formulario |
user_agent |
VARCHAR(512) | Navegador del cliente |
estado |
ENUM | pendiente / completado / firmado / expirado |
enviado_por |
INT FK | Usuario que generó el enlace |
enviado_via |
ENUM | whatsapp / email / link |
expira_en |
DATETIME NULL | Siempre NULL — el enlace no expira |
completado_en |
DATETIME | Fecha y hora en que el cliente completó el formulario |
hash_verificacion |
CHAR(64) | Sello de integridad SHA-256 del documento |
Roles y permisos
| Rol | Acceso |
|---|---|
| Admin | Crear, editar y eliminar plantillas desde el builder. Enviar formularios a cualquier paciente. Ver todos los envíos. Ver y descargar el PDF de cualquier formulario. |
| Enfermero | Enviar formularios existentes a sus pacientes. Ver solo sus propios envíos (enviado_por = su user_id). No puede crear ni editar plantillas. Puede firmar como profesional en los formularios que él mismo envió. |
| Cliente (público) | Accede a form_cliente.php?t=TOKEN sin ninguna autenticación. Llena y firma el formulario. Puede volver al mismo enlace en cualquier momento para ver el documento firmado y descargarlo como PDF. |
Flujo completo
1. ADMIN crea la plantilla
├─ Abre lab_formulario_builder.php (se abre en ventana nueva)
├─ Arrastra campos al canvas y los configura
├─ Configura el diseño del documento (logo, color, encabezado, pie de página)
└─ Guarda → POST api/lab/save_formulario.php → lab_formularios
2. ADMIN o ENFERMERO envía el formulario
├─ lab_formularios.php → botón "Enviar" → modal
├─ Busca y selecciona el paciente
├─ Previsualiza los campos que llegarán pre-llenados
├─ Selecciona el canal: WhatsApp o "solo link"
└─ POST api/lab/send_formulario.php
├─ Genera token de 64 hex chars: bin2hex(random_bytes(32))
├─ Crea fila en lab_form_envios (estado=pendiente, expira_en=NULL)
└─ Devuelve URL pública y mensaje preformateado para WhatsApp
3. CLIENTE recibe el enlace (por WhatsApp u otro medio)
├─ Abre form_cliente.php?t=TOKEN
├─ GET api/lab/submit_formulario.php?t=TOKEN → carga datos del formulario
└─ Si ya fue firmado antes → muestra pantalla de solo lectura con link al PDF
4. CLIENTE llena el formulario
├─ Campos "linked" llegan pre-llenados con datos del paciente (readonly si tienen valor)
├─ Campos vacíos linked son editables para que el cliente los complete
├─ Campos firma_profesional muestran aviso "uso exclusivo del profesional"
└─ Dibuja su firma (canvas) o adjunta una foto de firma
5. CLIENTE envía
├─ POST api/lab/submit_formulario.php
├─ Se genera hash SHA-256 (contenido + firma + ID + token + timestamp)
├─ Estado → "firmado" (si hay firma) o "completado" (sin firma)
└─ Pantalla de éxito con hash visible y botón para descargar el PDF
6. PROFESIONAL firma (si el formulario lo requiere)
├─ Admin/Enfermero abre ver_formulario_enviado.php?id=X con sesión activa
├─ Aparece canvas de firma en la posición del campo firma_profesional
├─ Dibuja su firma y hace clic en "Guardar firma"
└─ POST api/lab/firmar_profesional.php → guarda campo_id_svg en datos_cliente
7. ADMIN/ENFERMERO revisa el resultado
├─ lab_formularios.php → pestaña "Envíos" → icono "Ver respuesta"
└─ ver_formulario_enviado.php?id=X → documento HTML imprimible
8. VERIFICACIÓN pública de integridad
└─ verificar_formulario.php?h=HASH_SHA256
├─ Busca en lab_form_envios.hash_verificacion
└─ Muestra: nombre del formulario, paciente, fecha, estado y si el sello es válido
Tipos de campos del Builder
Campos de entrada
| Tipo | Descripción |
|---|---|
texto |
Campo de texto corto de una sola línea |
textarea |
Área de texto largo (varias líneas) |
numero |
Campo numérico |
fecha |
Selector de fecha |
hora |
Selector de hora |
select |
Lista desplegable con opciones configurables |
radio |
Selección única con opciones configurables |
checkbox |
Selección múltiple con opciones configurables |
lista_marcable |
Lista de ítems numerados con checkboxes |
Campos de firma
| Tipo | Descripción |
|---|---|
firma |
Firma del paciente — visible y editable en form_cliente.php |
firma_profesional |
Firma del profesional — bloqueada para el cliente; solo editable desde el panel admin/enfermero |
Campos de contenido
| Tipo | Descripción |
|---|---|
separador |
Separador visual o título de sección |
parrafo |
Bloque de texto estático (pre-formatado o flujo libre) |
parrafo_inline |
Párrafo con marcadores {nombre_completo}, {telefono}, etc. que se convierten en espacios editables si el valor está vacío |
Campos vinculados al paciente (tipo: linked)
Se auto-rellenan con los datos del paciente al momento de enviar. Si el valor existe → campo de solo lectura. Si está vacío → el cliente puede completarlo.
linked_key |
Dato que extrae |
|---|---|
nombre_completo |
Nombre completo del paciente |
numero_documento |
Número de documento |
tipo_documento |
Tipo de documento |
fecha_nacimiento |
Fecha de nacimiento |
telefono |
Teléfono |
email |
Correo electrónico |
eps |
EPS o aseguradora |
direccion |
Dirección |
Firma digital
Modos disponibles (configurados en la plantilla mediante firma_modos):
| Modo | Funcionamiento |
|---|---|
canvas |
El cliente dibuja su firma con el dedo o el mouse. Se captura con canvas.toDataURL('image/png'). |
foto |
El cliente sube una imagen desde su cámara o galería (<input accept="image/*" capture="environment">). Se convierte a base64 con FileReader. |
Ambos modos pueden estar activos simultáneamente en la misma plantilla.
Firma global vs. firma por campo:
- Si el esquema no incluye campos tipo
firma, se muestra una sección de firma global al pie del formulario. - Si el esquema incluye campos
firma, cada uno tiene su propio widget canvas independiente en la posición configurada dentro del formulario.
Enlace público y vigencia
- URL pública:
form_cliente.php?t=TOKEN - TOKEN: 64 caracteres hexadecimales generados con
bin2hex(random_bytes(32)). - Sin sesión: el cliente no necesita crear cuenta ni iniciar sesión.
- Sin vencimiento: la columna
expira_enexiste en la tabla pero siempre esNULL. El enlace es permanente. - Bloqueo por estado: si el formulario ya fue completado o firmado, el enlace muestra la pantalla de solo lectura. No permite modificar la respuesta.
- Idempotencia: si el cliente reintenta enviar (por error de red, por ejemplo), el sistema devuelve éxito con los datos ya guardados en lugar de crear un duplicado.
PDF y visualización del documento
No se usa ninguna librería de generación de PDF en el backend. El documento es la página ver_formulario_enviado.php con estilos @media print. El usuario puede imprimirla o guardarla como PDF directamente desde el navegador.
Contenido del documento impreso:
- Encabezado con logo, nombre, subtítulo, datos de contacto y color corporativo
- Datos del paciente (nombre, documento, fecha de nacimiento, teléfono, EPS)
- Respuestas del formulario campo por campo, en el orden del esquema
- Imagen de la firma del paciente
- Firma del profesional (si fue completada)
- Sello SHA-256 con link para verificar autenticidad
- Pie de página con fecha de generación e ID del documento
Formas de acceder al documento:
| URL | Quién puede acceder |
|---|---|
ver_formulario_enviado.php?id=X |
Admin (cualquier formulario) o Enfermero (solo los que él envió). Requiere sesión. |
ver_formulario_enviado.php?t=TOKEN |
Cliente u cualquier persona con el enlace. Sin sesión. Solo si el estado es firmado o completado. |
Sello de integridad SHA-256
Al guardar la respuesta del cliente, el sistema genera un hash SHA-256 que vincula de forma única el contenido del formulario con la firma y el momento en que se completó.
Construcción del hash (en Formulario::guardarRespuesta()):
SHA-256 de:
JSON de los datos del cliente
+ firma SVG/PNG del paciente
+ ID interno del envío
+ token del enlace
+ timestamp del momento de registro
¿Para qué sirve? Cualquier persona con el hash puede ir a verificar_formulario.php?h=HASH para confirmar que:
- El documento existe en la base de datos.
- El nombre del formulario y del paciente.
- La fecha en que fue completado.
- El estado actual (firmado / completado).
Si el documento fue alterado, el hash no coincidirá y la verificación fallará.
Firma del profesional
Algunos formularios requieren que un profesional de salud también firme el documento, además del paciente.
Flujo:
- Al diseñar la plantilla en el builder se agrega un campo
tipo: firma_profesionalen la posición deseada. - Cuando el cliente llena el formulario en
form_cliente.php, ese campo muestra solo un aviso: "Uso exclusivo del profesional de salud". El cliente no puede interactuar con él. - Una vez que el cliente ha completado y enviado el formulario, el admin o enfermero abre
ver_formulario_enviado.php?id=Xcon sesión activa y verá el canvas de firma en esa posición. - El profesional dibuja su firma y hace clic en "Guardar firma".
- La firma se guarda mediante POST a
api/lab/firmar_profesional.php.
Validaciones en el servidor:
- Requiere sesión activa (
isUserLoggedIn()). - Si el usuario es enfermero, solo puede firmar en formularios que él mismo envió.
- Valida que el
campo_idcorresponde a un campotipo: firma_profesionalen el esquema del formulario. - Valida que la imagen enviada sea un data URI de imagen válido.
Si el formulario se accede via
?t=TOKEN(cliente público), el canvas no aparece. En su lugar se muestra un aviso "Pendiente de firma del profesional" (solo visible en pantalla, no en el PDF impreso).
API Endpoints
| Endpoint | Método | Autenticación | Descripción |
|---|---|---|---|
api/lab/get_formularios.php |
GET | Sesión | Lista plantillas. ?id=X para una sola. ?envios=1 para lista de envíos. |
api/lab/save_formulario.php |
POST | Admin | Crear, editar o eliminar una plantilla. |
api/lab/send_formulario.php |
POST | Admin / Enfermero | Crear instancia de envío. Devuelve URL pública y mensaje para WhatsApp. |
api/lab/submit_formulario.php |
GET | Público | Cargar el formulario por token (sin sesión). |
api/lab/submit_formulario.php |
POST | Público | Guardar la respuesta y firma del cliente. |
api/lab/firmar_profesional.php |
POST | Sesión | Guardar la firma del profesional en un campo firma_profesional. |
Documentación generada para uso interno del equipo.