523 lines
25 KiB
Markdown
523 lines
25 KiB
Markdown
# 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)](#1-módulo-de-agendamiento-domicilios)
|
|
- [¿Qué es?](#qué-es)
|
|
- [Archivos involucrados](#archivos-involucrados)
|
|
- [Base de datos](#base-de-datos)
|
|
- [Roles y permisos](#roles-y-permisos)
|
|
- [Flujo de estados](#flujo-de-estados)
|
|
- [Funcionalidades](#funcionalidades)
|
|
- [API Endpoints](#api-endpoints)
|
|
2. [Módulo de Formularios](#2-módulo-de-formularios)
|
|
- [¿Qué es?](#qué-es-1)
|
|
- [Archivos involucrados](#archivos-involucrados-1)
|
|
- [Base de datos](#base-de-datos-1)
|
|
- [Roles y permisos](#roles-y-permisos-1)
|
|
- [Flujo completo](#flujo-completo)
|
|
- [Tipos de campos del Builder](#tipos-de-campos-del-builder)
|
|
- [Firma digital](#firma-digital)
|
|
- [Enlace público y vigencia](#enlace-público-y-vigencia)
|
|
- [PDF y visualización del documento](#pdf-y-visualización-del-documento)
|
|
- [Sello de integridad SHA-256](#sello-de-integridad-sha-256)
|
|
- [Firma del profesional](#firma-del-profesional)
|
|
- [API Endpoints](#api-endpoints-1)
|
|
|
|
---
|
|
|
|
## 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](#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.php` lo redirige inmediatamente a `enfermero_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.php` que 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_en` existe en la tabla pero siempre es `NULL`. 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:**
|
|
1. Al diseñar la plantilla en el builder se agrega un campo `tipo: firma_profesional` en la posición deseada.
|
|
2. 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.
|
|
3. Una vez que el cliente ha completado y enviado el formulario, el admin o enfermero abre `ver_formulario_enviado.php?id=X` con sesión activa y verá el canvas de firma en esa posición.
|
|
4. El profesional dibuja su firma y hace clic en "Guardar firma".
|
|
5. 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_id` corresponde a un campo `tipo: firma_profesional` en 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.*
|