Documentación: diagramas, kiosko y chat, catálogos, respaldos y endpoints documentados
Diagramas en texto dentro de bloques de código, en vez de capturas: se editan
como texto, no pesan en el repositorio y no quedan desactualizados solos. Se
agregan el recorrido de un turno, quién firma cada consentimiento, el paso de
una muestra pendiente entre visitas y la línea de tiempo de las tomas seriadas.
Páginas nuevas del manual: kiosko y pantallas de TV (las dos que funcionan sin
nadie operándolas), y chat de WhatsApp, que explica por qué el bot deja de
responder cuando un operador toma la conversación y de dónde sale el límite de
24 horas.
Páginas técnicas nuevas: registro de exámenes, y los catálogos del laboratorio
agrupados en una sola página por compartir la misma forma. Operación suma
respaldos y recuperación, incluyendo qué datos históricos no son recuperables.
Los 10 endpoints que no tenían comentario de cabecera ahora lo tienen, así que
la tabla generada por {{endpoints}} queda completa: 83 de 83.
DOCUMENTACION_LAB.md y README_LAB.md quedan como puntero al módulo;
WEBHOOK_ENDPOINTS.md se elimina por estar ya migrado a la sección técnica.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
81c007c516
commit
71c9dfd424
+5
-518
@@ -1,522 +1,9 @@
|
||||
# Documentación del Sistema de Laboratorio
|
||||
# Obsoleto
|
||||
|
||||
> **Sistema**: Laboratorio Clínico — Módulos de Agendamiento y Formularios
|
||||
> **Última actualización**: 27/03/2026
|
||||
Este documento quedó desactualizado y se conserva solo por historial de git.
|
||||
|
||||
---
|
||||
La documentación vigente está **dentro del sistema**, en el módulo Soporte:
|
||||
|
||||
## Tabla de contenidos
|
||||
/erp.php?m=soporte&v=documentacion
|
||||
|
||||
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.*
|
||||
Ver `README_DOCS.md` para saber cómo se organiza y cómo agregar páginas.
|
||||
|
||||
+5
-125
@@ -1,129 +1,9 @@
|
||||
# Módulo Administrativo — Laboratorio Clínico
|
||||
# Obsoleto
|
||||
|
||||
Módulo add-on para el sistema de chatbot WhatsApp que permite gestionar órdenes médicas recibidas como imágenes, domicilios, enfermeras y pacientes.
|
||||
Este documento quedó desactualizado y se conserva solo por historial de git.
|
||||
|
||||
---
|
||||
La documentación vigente está **dentro del sistema**, en el módulo Soporte:
|
||||
|
||||
## Instalación
|
||||
/erp.php?m=soporte&v=documentacion
|
||||
|
||||
### 1. Ejecutar migraciones de base de datos
|
||||
|
||||
```bash
|
||||
php migrations/20260302_lab_run_migrations.php
|
||||
```
|
||||
|
||||
Crea 7 tablas nuevas sin modificar las existentes:
|
||||
- `lab_pacientes`
|
||||
- `lab_enfermeras`
|
||||
- `lab_ordenes_medicas`
|
||||
- `lab_domicilios`
|
||||
- `lab_asignaciones`
|
||||
- `lab_autorizaciones`
|
||||
- `lab_actividad_admin`
|
||||
|
||||
Para deshacer:
|
||||
```bash
|
||||
php migrations/20260302_lab_run_migrations.php --rollback
|
||||
```
|
||||
|
||||
### 2. Verificar instalación
|
||||
|
||||
Accede desde el navegador (con sesión admin activa):
|
||||
```
|
||||
https://tu-servidor/lab_status.php
|
||||
```
|
||||
|
||||
O desde CLI:
|
||||
```bash
|
||||
php lab_status.php
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Archivos del módulo
|
||||
|
||||
### Vistas PHP
|
||||
| Archivo | Descripción |
|
||||
|---|---|
|
||||
| `lab_dashboard.php` | Panel principal con estadísticas en tiempo real |
|
||||
| `lab_ordenes.php` | Gestión de órdenes médicas (estados, imágenes, historial) |
|
||||
| `lab_pacientes.php` | CRUD de pacientes, vinculación con usuarios WhatsApp |
|
||||
| `lab_domicilios.php` | Agenda de domicilios y asignación de enfermeras |
|
||||
| `lab_enfermeras.php` | CRUD de enfermeras y visualización de agenda diaria |
|
||||
| `lab_reportes.php` | Trazabilidad, log de actividad, exportación CSV |
|
||||
| `lab_status.php` | Verificador de estado del módulo |
|
||||
|
||||
### Clases (models)
|
||||
Ubicadas en `classes/lab/`:
|
||||
- `ActividadAdmin.php` — Base de trazabilidad
|
||||
- `Paciente.php` — Modelo de pacientes
|
||||
- `Enfermera.php` — Modelo de enfermeras
|
||||
- `OrdenMedica.php` — Modelo de órdenes médicas con flujo de estados
|
||||
- `Domicilio.php` — Modelo de domicilios con flujo de estados
|
||||
- `Asignacion.php` — Modelo de asignaciones enfermera ↔ domicilio
|
||||
|
||||
### API REST
|
||||
Ubicados en `api/lab/`:
|
||||
| Endpoint | Método | Descripción |
|
||||
|---|---|---|
|
||||
| `get_pacientes.php` | GET | Lista paginada de pacientes |
|
||||
| `save_paciente.php` | POST | Crear/actualizar paciente |
|
||||
| `get_ordenes.php` | GET | Lista/detalle de órdenes |
|
||||
| `save_orden.php` | POST | Crear/actualizar orden |
|
||||
| `autorizar_orden.php` | POST | Cambiar estado de una orden |
|
||||
| `get_domicilios.php` | GET | Lista/detalle de domicilios |
|
||||
| `save_domicilio.php` | POST | Crear/actualizar domicilio |
|
||||
| `get_enfermeras.php` | GET | Lista de enfermeras + agenda |
|
||||
| `save_enfermera.php` | POST | Crear/actualizar enfermera |
|
||||
| `get_asignaciones.php` | GET | Asignaciones por fecha |
|
||||
| `save_asignacion.php` | POST | Asignar/liberar/completar enfermera |
|
||||
| `get_actividad.php` | GET | Log de actividad con filtros |
|
||||
| `get_stats.php` | GET | Estadísticas para dashboard |
|
||||
| `crear_desde_whatsapp.php` | GET/POST | Crear orden desde conversación activa |
|
||||
|
||||
---
|
||||
|
||||
## Flujos de estado
|
||||
|
||||
### Órdenes médicas
|
||||
```
|
||||
pendiente → en_revision → autorizada → en_domicilio → completada
|
||||
↘ rechazada
|
||||
```
|
||||
|
||||
### Domicilios
|
||||
```
|
||||
programado → confirmado → en_camino → en_domicilio → completado
|
||||
↘ cancelado
|
||||
↘ reprogramado
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integración con el chatbot
|
||||
|
||||
En `conversations.php`, los mensajes de imagen entrantes tienen un botón **<i class="fas fa-flask"></i>** (verde) en las acciones del mensaje. Al hacer click:
|
||||
|
||||
1. Se abre un modal con la imagen adjunta
|
||||
2. El operador busca o selecciona un paciente (o usa el contacto de la conversación)
|
||||
3. Completa datos opcionales (médico, exámenes, ayuno)
|
||||
4. Se crea la orden en estado `pendiente`
|
||||
|
||||
---
|
||||
|
||||
## Exportaciones CSV
|
||||
|
||||
Disponibles desde `lab_reportes.php`:
|
||||
- **Órdenes médicas** del período — incluye estado, médico, exámenes
|
||||
- **Domicilios** del período — incluye enfermera asignada, dirección, estado
|
||||
- **Pacientes** — catálogo completo con total de órdenes
|
||||
|
||||
---
|
||||
|
||||
## Requisitos
|
||||
|
||||
- PHP 8.2+
|
||||
- MariaDB 10.11+ (o MySQL 8+)
|
||||
- Bootstrap 5.3 (ya incluido en el sistema)
|
||||
- Font Awesome 6.4 (ya incluido en el sistema)
|
||||
- `uploads/media/` con permisos de escritura (755/775)
|
||||
Ver `README_DOCS.md` para saber cómo se organiza y cómo agregar páginas.
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
# Webhook WhatsApp — Endpoints y Características
|
||||
|
||||
## Endpoint principal
|
||||
|
||||
```
|
||||
URL: /api/webhook.php
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GET — Verificación de webhook
|
||||
|
||||
```
|
||||
GET /api/webhook.php?hub.mode=subscribe&hub.verify_token=TOKEN&hub.challenge=CHALLENGE
|
||||
```
|
||||
|
||||
### Parámetros que envía Meta
|
||||
| Parámetro | Valor esperado |
|
||||
|---|---|
|
||||
| `hub.mode` | `subscribe` |
|
||||
| `hub.verify_token` | El token configurado en `system_config.webhook_verify_token` |
|
||||
| `hub.challenge` | Número aleatorio que debe devolverse tal cual |
|
||||
|
||||
### ⚠️ Bug conocido
|
||||
El código lee `$_GET['hub_verify_token']` (con guión bajo), pero PHP convierte los puntos a guiones bajos automáticamente al parsear `$_GET`, por lo que **funciona correctamente**.
|
||||
|
||||
### Respuesta exitosa
|
||||
```
|
||||
HTTP 200
|
||||
Body: {challenge}
|
||||
```
|
||||
|
||||
### Respuesta fallida
|
||||
```
|
||||
HTTP 403
|
||||
Body: {"error":"Token de verificación inválido"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## POST — Recepción de eventos
|
||||
|
||||
```
|
||||
POST /api/webhook.php
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### Estructura del payload esperado (Meta Cloud API)
|
||||
|
||||
```json
|
||||
{
|
||||
"object": "whatsapp_business_account",
|
||||
"entry": [{
|
||||
"id": "WABA_ID",
|
||||
"changes": [{
|
||||
"field": "messages",
|
||||
"value": {
|
||||
"messaging_product": "whatsapp",
|
||||
"metadata": {
|
||||
"phone_number_id": "PHONE_NUMBER_ID"
|
||||
},
|
||||
"contacts": [{
|
||||
"wa_id": "573001234567",
|
||||
"profile": { "name": "Nombre Contacto" }
|
||||
}],
|
||||
"messages": [{
|
||||
"from": "573001234567",
|
||||
"id": "wamid.XXX",
|
||||
"timestamp": "1234567890",
|
||||
"type": "text",
|
||||
"text": { "body": "Hola" }
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Tipos de mensaje soportados
|
||||
| `type` | Descripción |
|
||||
|---|---|
|
||||
| `text` | Texto plano |
|
||||
| `image` | Imagen (con caption opcional) |
|
||||
| `audio` | Audio / nota de voz |
|
||||
| `video` | Video |
|
||||
| `document` | Documento / PDF |
|
||||
| `sticker` | Sticker |
|
||||
| `reaction` | Reacción emoji a otro mensaje |
|
||||
| `interactive` | Respuesta de lista o botón |
|
||||
|
||||
### El campo `field` del change puede ser
|
||||
- `messages` → mensajes entrantes y estados
|
||||
- `conversations` → alias aceptado también
|
||||
|
||||
### Eventos de estado (statuses)
|
||||
```json
|
||||
"statuses": [{
|
||||
"id": "wamid.XXX",
|
||||
"status": "sent|delivered|read|failed",
|
||||
"recipient_id": "573001234567"
|
||||
}]
|
||||
```
|
||||
|
||||
### Respuesta exitosa
|
||||
```
|
||||
HTTP 200
|
||||
Body: {"status":"success"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuración necesaria en `system_config` (BD)
|
||||
|
||||
| config_key | Descripción |
|
||||
|---|---|
|
||||
| `whatsapp_token` | Access Token de Meta |
|
||||
| `whatsapp_phone_number_id` | Phone Number ID de la línea |
|
||||
| `webhook_verify_token` | Token de verificación del webhook |
|
||||
| `whatsapp_api_url` | `https://graph.facebook.com/v22.0/` |
|
||||
|
||||
---
|
||||
|
||||
## Variables de entorno equivalentes (`.env`)
|
||||
|
||||
```env
|
||||
WHATSAPP_TOKEN=
|
||||
WHATSAPP_PHONE_NUMBER_ID=
|
||||
WEBHOOK_VERIFY_TOKEN=
|
||||
WHATSAPP_API_URL=https://graph.facebook.com/v22.0/
|
||||
DB_HOST=
|
||||
DB_PORT=3306
|
||||
DB_NAME=
|
||||
DB_USER=
|
||||
DB_PASS=
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tablas BD que usa el webhook
|
||||
|
||||
| Tabla | Uso |
|
||||
|---|---|
|
||||
| `users` | Crea o busca usuario por `phone_number` |
|
||||
| `conversations` | Guarda cada mensaje (deduplicado por `message_id`) |
|
||||
| `webhook_logs` | Registra el payload crudo de cada POST |
|
||||
| `notifications` | Crea aviso de nuevo mensaje entrante |
|
||||
| `media_queue` | Encola media que no pudo descargarse en el momento |
|
||||
| `system_config` | Lee tokens y configuración |
|
||||
|
||||
---
|
||||
|
||||
## Seguridad — pendiente de implementar
|
||||
|
||||
- No valida la firma `X-Hub-Signature-256` en el POST.
|
||||
- Se recomienda agregar antes de procesar:
|
||||
```php
|
||||
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';
|
||||
$expected = 'sha256=' . hash_hmac('sha256', $input, APP_SECRET);
|
||||
if (!hash_equals($expected, $signature)) {
|
||||
http_response_code(401);
|
||||
exit;
|
||||
}
|
||||
```
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* GET ?id=N — Detalle de un examen del catálogo con sus ítems.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireLogin();
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* GET ?exam_id=N — Tarifas de un examen por empresa o convenio.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireLogin();
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* GET ?q=&categoria=&page=&limit= — Catálogo de exámenes, paginado y filtrable.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireLogin();
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* POST — Crea o actualiza un examen del catálogo. Requiere administrador.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireAdmin();
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') jsonError('Método no permitido', 405);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* POST — Crea o actualiza un ítem (analito) de un examen. Requiere administrador.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireAdmin();
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') jsonError('Método no permitido', 405);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* POST — Crea o actualiza la tarifa de un examen. Requiere administrador.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireAdmin();
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') jsonError('Método no permitido', 405);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* POST { id } — Elimina un médico del catálogo.
|
||||
*/
|
||||
require_once __DIR__ . '/../../../config/config.php';
|
||||
if (!isUserLoggedIn()) { http_response_code(401); echo json_encode(['ok'=>false,'error'=>'No autorizado']); exit; }
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* GET — Lista de médicos solicitantes.
|
||||
*/
|
||||
require_once __DIR__ . '/../../../config/config.php';
|
||||
if (!isUserLoggedIn()) { http_response_code(401); echo json_encode(['ok'=>false,'error'=>'No autorizado']); exit; }
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* POST — Crea o actualiza un médico del catálogo.
|
||||
*/
|
||||
require_once __DIR__ . '/../../../config/config.php';
|
||||
if (!isUserLoggedIn()) { http_response_code(401); echo json_encode(['ok'=>false,'error'=>'No autorizado']); exit; }
|
||||
|
||||
|
||||
@@ -34,6 +34,27 @@ Casi siempre es una de estas dos:
|
||||
| **Formularios** | Consentimientos y fichas; diseño y envíos |
|
||||
| **Soporte** | Esta documentación |
|
||||
|
||||
## El recorrido de un paciente
|
||||
|
||||
Desde que saca su turno hasta que se va:
|
||||
|
||||
```
|
||||
KIOSKO RECEPCIÓN TOMA DE MUESTRAS
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────┐ llama ┌──────┐ deriva ┌──────────────┐ ┌────────────┐
|
||||
│espera├──────────►│recep.├───────────►│ espera lugar ├──►│ en servicio│
|
||||
└──┬───┘ └──┬───┘ └──────────────┘ └──────┬─────┘
|
||||
│ │ │
|
||||
│ no responde │ ▼
|
||||
└──────────────────┴──────────► ausente ┌────────────────┐
|
||||
│ finalizado │
|
||||
cancelado └────────────────┘
|
||||
cuenta para facturar
|
||||
```
|
||||
|
||||
Un turno **nunca se borra**. Si el paciente no aparece se marca *ausente*; si no se hace, *cancelado*. Los dos quedan registrados, y ninguno cuenta como facturación.
|
||||
|
||||
## Cosas que conviene saber desde el principio
|
||||
|
||||
**Los turnos no se borran.** Se cancelan o se marcan como ausente, pero quedan registrados. Es a propósito: el historial tiene valor clínico y administrativo.
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Kiosko y pantallas de TV
|
||||
|
||||
Las dos pantallas que funcionan solas, sin nadie operándolas. Conviene entenderlas porque cuando fallan, el que se entera primero es quien está en recepción.
|
||||
|
||||
## El kiosko
|
||||
|
||||
El tótem de la entrada, donde el paciente saca su turno sin ayuda.
|
||||
|
||||
```
|
||||
PACIENTE LLEGA
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ Elige tipo │ general, preferencial, embarazada,
|
||||
│ de turno │ solo entrega de muestras…
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│Datos básicos │ nombre y celular (opcional)
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ Imprime │──► el turno aparece en la pantalla de TV
|
||||
│ su turno │ y en la cola de recepción
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
Es una de las **dos únicas pantallas públicas** del sistema: no pide usuario ni contraseña, porque nadie va a iniciar sesión en el tótem de la entrada.
|
||||
|
||||
### Prioridades
|
||||
|
||||
El tipo de turno que elige el paciente define su lugar en la cola. Las prioridades las configura un administrador; quien atiende no necesita hacer nada: **Llamar siguiente** ya respeta el orden.
|
||||
|
||||
### Si el paciente deja su celular
|
||||
|
||||
Puede recibir por WhatsApp el aviso de su turno y los consentimientos para firmar desde el teléfono mientras espera. Vale la pena insistirle en que lo deje.
|
||||
|
||||
### Cuando el kiosko falla
|
||||
|
||||
Un turno siempre se puede crear a mano desde recepción. El kiosko es una comodidad, no un requisito — si está caído, la atención sigue.
|
||||
|
||||
## Pantalla de TV
|
||||
|
||||
La de la sala de espera. Muestra el turno que se está llamando y la cola, y reproduce contenido del laboratorio de fondo.
|
||||
|
||||
También es pública: se abre en el navegador del televisor y se deja andando.
|
||||
|
||||
### El contenido de fondo
|
||||
|
||||
Es una lista de videos e imágenes que se reproducen en bucle, uno detrás de otro:
|
||||
|
||||
```
|
||||
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
|
||||
│ video 1 │──►│ imagen │──►│ video 2 │──►│ imagen │──┐
|
||||
│ hasta │ │ 8 seg │ │ hasta │ │ 10 seg │ │
|
||||
│ el final│ │ │ │ el final│ │ │ │
|
||||
└─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||||
▲ │
|
||||
└──────────────────── vuelve a empezar ────────────┘
|
||||
```
|
||||
|
||||
Los videos van completos; a las imágenes se les fija cuántos segundos duran. Se administra desde **Configuración del turnero → Pantalla TV**: se suben, se reordenan arrastrando y se eliminan de a uno.
|
||||
|
||||
### Si la pantalla se queda pegada
|
||||
|
||||
Recargá la página en el televisor. Si el contenido no cambió, verificá que la lista tenga elementos activos en la configuración.
|
||||
|
||||
## Verificar paciente
|
||||
|
||||
Una consulta rápida por cédula para ver la ficha y el historial de alguien, sin abrir su turno. Útil cuando el paciente pregunta algo en el mostrador y no querés perder lo que estás haciendo.
|
||||
@@ -45,6 +45,22 @@ Se admite pago combinado — efectivo más tarjeta, por ejemplo.
|
||||
|
||||
### 5. Consentimientos
|
||||
|
||||
Quién firma qué, y dónde:
|
||||
|
||||
```
|
||||
RECEPCIÓN TOMA DE MUESTRAS
|
||||
┌─────────────────────┐ ┌──────────────────────┐
|
||||
│ Consentimiento │ │ Datos Toma de │
|
||||
│ pruebas de lab │ │ Muestras (F-LAB-08) │
|
||||
│ │ │ │
|
||||
│ firma: EL PACIENTE │ │ firma: EL PERSONAL │
|
||||
│ vía WhatsApp │ │ en la estación │
|
||||
└─────────────────────┘ └──────────────────────┘
|
||||
obligatorio obligatorio SIEMPRE
|
||||
salvo "solo entrega" (incluso solo entrega)
|
||||
```
|
||||
|
||||
|
||||
Los que hagan falta aparecen listados con su estado. Se envían al WhatsApp del paciente, que los firma desde el celular.
|
||||
|
||||
**No podés guardar la solicitud si quedan consentimientos sin firmar**, salvo que sea una visita de *solo entrega de muestras*.
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
roles: recepcionista, lab_recepcion, operador_bot, supervisor
|
||||
---
|
||||
|
||||
# Chat de WhatsApp
|
||||
|
||||
La línea de WhatsApp del laboratorio la atiende un bot, pero cuando hace falta una persona, la conversación pasa a un operador. Esta es esa pantalla.
|
||||
|
||||
## Cómo se reparte el trabajo
|
||||
|
||||
```
|
||||
MENSAJE DEL PACIENTE
|
||||
│
|
||||
▼
|
||||
┌─────────────┐ no ┌──────────────────────┐
|
||||
│ ¿Aceptó los ├────────►│ Le pide aceptar y │
|
||||
│ términos? │ │ no avanza hasta que │
|
||||
└──────┬──────┘ │ responda ACEPTO │
|
||||
│ sí └──────────────────────┘
|
||||
▼
|
||||
┌─────────────┐ sí ┌──────────────────────┐
|
||||
│ ¿La tomó un ├────────►│ El bot NO interviene │
|
||||
│ operador? │ │ Respondés vos │
|
||||
└──────┬──────┘ └──────────────────────┘
|
||||
│ no
|
||||
▼
|
||||
┌─────────────┐ fuera ┌──────────────────────┐
|
||||
│ ¿Está en ├────────►│ Responde con el │
|
||||
│ horario? │ │ mensaje de fuera de │
|
||||
└──────┬──────┘ │ horario │
|
||||
│ dentro └──────────────────────┘
|
||||
▼
|
||||
El bot responde
|
||||
```
|
||||
|
||||
Lo importante: **cuando tomás una conversación, el bot deja de responder ahí**. No hay riesgo de que le conteste encima al paciente mientras vos estás escribiendo.
|
||||
|
||||
## Atender una conversación
|
||||
|
||||
La lista muestra los hilos con mensajes recientes. Al abrir uno ves el historial completo y podés responder.
|
||||
|
||||
Si el paciente ya está registrado, se ve su ficha; si no, se puede crear desde ahí mismo.
|
||||
|
||||
## La ventana de 24 horas
|
||||
|
||||
Es una regla de WhatsApp, no del sistema:
|
||||
|
||||
> Podés escribir libremente durante **24 horas** desde el último mensaje del paciente. Pasado ese plazo, solo se le puede escribir con una **plantilla aprobada**.
|
||||
|
||||
Por eso a veces el sistema no te deja mandar un texto libre y ofrece plantillas. No es una falla: es la restricción de WhatsApp.
|
||||
|
||||
Las plantillas las crea y aprueba Meta. Si necesitás una nueva para un caso que se repite, pedila a un administrador — el trámite lleva días.
|
||||
|
||||
## Términos y condiciones
|
||||
|
||||
Todo contacto nuevo debe aceptar los términos antes de que el bot converse. Responde **ACEPTO** o **NO ACEPTO**.
|
||||
|
||||
Se le vuelven a pedir cuando pasan 6 meses o cuando se publica una versión nueva. Si un paciente dice que no puede abrir el documento de términos, avisá: puede ser que el enlace esté caído, y eso lo resuelve un administrador.
|
||||
|
||||
## Problemas frecuentes
|
||||
|
||||
**El paciente dice que escribió y nadie le respondió.**
|
||||
Revisá si la conversación quedó tomada por un operador que no siguió. En ese estado el bot no responde y queda esperando a una persona.
|
||||
|
||||
**No me deja enviar un mensaje.**
|
||||
Pasaron más de 24 horas desde el último mensaje del paciente. Usá una plantilla.
|
||||
|
||||
**El paciente no recibe los consentimientos.**
|
||||
Verificá el número en su ficha. Si está bien y aun así no llegan, es problema de plantilla — avisá a un administrador.
|
||||
@@ -28,6 +28,19 @@ Al rechazar hay que indicar el motivo. Ese motivo queda registrado y se ve despu
|
||||
|
||||
### Muestras de visitas anteriores
|
||||
|
||||
```
|
||||
VISITA 1 · lunes VISITA 2 · jueves
|
||||
┌────────────────────┐ ┌────────────────────┐
|
||||
│ Turno A-042 │ │ Turno B-017 │
|
||||
│ │ │ │
|
||||
│ Sangre recibida │ │ Orina recibida │
|
||||
│ Orina PENDIENTE ├───────────────►│ └ visita anterior│
|
||||
└────────────────────┘ reaparece └────────────────────┘
|
||||
finalizado sola │
|
||||
NO se modifica ◄─────────────────────────────
|
||||
quedan enlazados
|
||||
```
|
||||
|
||||
Si el paciente quedó debiendo una muestra otro día, te aparece con una etiqueta ámbar **visita anterior**, e incluye los exámenes de aquella orden para que sepas de qué se trataba.
|
||||
|
||||
Se reciben con un clic, igual que cualquier otra. Al hacerlo, los dos turnos quedan enlazados: desde el historial podés saltar de uno al otro.
|
||||
@@ -48,6 +61,22 @@ Lo firmás vos, no el paciente.
|
||||
|
||||
Para exámenes que requieren varias tomas en el tiempo: curvas de glicemia, prolactina, cortisol, test de Sullivan.
|
||||
|
||||
```
|
||||
Glicemia pre y post carga
|
||||
|
||||
min 0 min 30 min 60 min 120
|
||||
│ │ │ │
|
||||
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
|
||||
│ ✔ │ ────► │ ✔ │ ────► │ │ ... │ │
|
||||
└─────┘ 30min └─────┘ 30min └─────┘ └─────┘
|
||||
07:28 08:06 pendiente bloqueada
|
||||
M. Monterrosa Y. Parada ▲
|
||||
└ cuenta regresiva
|
||||
|
||||
Cada toma guarda SU hora y QUIÉN la firmó. Si cambia
|
||||
el turno del personal, cada firma conserva su nombre.
|
||||
```
|
||||
|
||||
Cómo funciona:
|
||||
|
||||
1. **Marcá el examen.** El formulario muestra solo las tomas de ese examen; si el paciente tiene dos exámenes seriados, muestra las de ambos.
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# Respaldos y recuperación
|
||||
|
||||
Qué hay que respaldar, y qué se pierde si no está.
|
||||
|
||||
## Las tres cosas a respaldar
|
||||
|
||||
```
|
||||
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
|
||||
│ BASE DE DATOS │ │ ARCHIVOS SUBIDOS │ │ CÓDIGO │
|
||||
│ │ │ │ │ │
|
||||
│ 91 tablas │ │ uploads/terms/ │ │ repositorio git │
|
||||
│ pacientes, turnos, │ │ uploads/turnero/ │ │ │
|
||||
│ formularios, │ │ │ │ ya respaldado por │
|
||||
│ firmas │ │ NO están en git │ │ estar en el remoto │
|
||||
└────────────────────┘ └────────────────────┘ └────────────────────┘
|
||||
crítico crítico cubierto
|
||||
```
|
||||
|
||||
El código está a salvo por estar versionado. Los otros dos **no tienen respaldo automático por el solo hecho de existir**.
|
||||
|
||||
## Base de datos
|
||||
|
||||
Es lo único irreemplazable. Contiene historia clínica, consentimientos firmados y facturación — información con valor legal y sin forma de reconstruirse.
|
||||
|
||||
```bash
|
||||
mysqldump -h <host> -u <usuario> -p <base> \
|
||||
--single-transaction --routines --triggers \
|
||||
| gzip > respaldo_$(date +%F).sql.gz
|
||||
```
|
||||
|
||||
`--single-transaction` evita bloquear las tablas mientras corre, así se puede hacer con el sistema en uso.
|
||||
|
||||
### Qué contiene lo crítico
|
||||
|
||||
| Tabla | Por qué importa |
|
||||
|---|---|
|
||||
| `lab_pacientes` | Fichas clínicas |
|
||||
| `turnero_consentimientos`, `lab_form_envios` | **Formularios firmados** — valor legal |
|
||||
| `turnero_turnos`, `turnero_solicitudes` | Historial de atención y facturación |
|
||||
| `terms_acceptance` | Aceptación de términos, ~5.000 registros |
|
||||
| `admin_users`, `roles`, `role_modules` | Acceso al sistema |
|
||||
|
||||
Las firmas se guardan como imagen **dentro** de las tablas, no como archivos sueltos. Un respaldo de la base las incluye.
|
||||
|
||||
## Archivos subidos
|
||||
|
||||
```
|
||||
uploads/terms/ documentos de términos y condiciones
|
||||
uploads/turnero/tv_media/ videos e imágenes de la pantalla de TV
|
||||
```
|
||||
|
||||
**No están en el repositorio.** Al mover el sistema de servidor hay que copiarlos aparte, o los enlaces quedan apuntando a archivos que ya no existen.
|
||||
|
||||
Es exactamente lo que pasó con el documento de términos cuando cambió el dominio: la base seguía apuntando a una URL que ya no respondía.
|
||||
|
||||
## Antes de un cambio riesgoso
|
||||
|
||||
Si vas a tocar datos en producción, respaldá **solo lo que vas a tocar**:
|
||||
|
||||
```bash
|
||||
mysqldump -h <host> -u <usuario> -p <base> role_modules admin_users \
|
||||
> antes_del_cambio.sql
|
||||
```
|
||||
|
||||
Es rápido y suele alcanzar. Un respaldo completo para cambiar una columna es desproporcionado; no tener ninguno es imprudente.
|
||||
|
||||
## Verificar que el respaldo sirve
|
||||
|
||||
Un respaldo que nunca se restauró no es un respaldo, es un archivo:
|
||||
|
||||
```bash
|
||||
gunzip -t respaldo_2026-08-03.sql.gz # ¿está íntegro?
|
||||
zcat respaldo_2026-08-03.sql.gz | head -40 # ¿tiene lo que esperás?
|
||||
```
|
||||
|
||||
Lo ideal es restaurarlo de vez en cuando en una base de prueba y comprobar que el sistema arranca contra ella.
|
||||
|
||||
## Qué NO es recuperable
|
||||
|
||||
Aunque tengas respaldos, hay datos que nunca se guardaron y no hay de dónde sacarlos:
|
||||
|
||||
| Dato | Desde cuándo existe |
|
||||
|---|---|
|
||||
| Quién creó cada consentimiento del turnero | 3 de agosto de 2026 |
|
||||
| Quién firmó cada toma de F-LAB-28 | 3 de agosto de 2026 |
|
||||
| Cédula del personal no enfermero | 3 de agosto de 2026 |
|
||||
|
||||
Los registros anteriores tienen esos campos vacíos, y **no hay traza de auditoría** que permita reconstruirlos. Vale como advertencia: cuando se agrega una columna para registrar quién hizo algo, lo anterior se pierde.
|
||||
@@ -0,0 +1,54 @@
|
||||
# Registro de exámenes
|
||||
|
||||
Registro de exámenes realizados en sede: creación de órdenes, toma de muestras e ingreso de resultados. Es de los módulos nuevos — todo su código vive dentro de `modules/registro_exams/`.
|
||||
|
||||
## Vistas
|
||||
|
||||
| Vista | Qué hace |
|
||||
|---|---|
|
||||
| `lista` | Órdenes con filtros y estado |
|
||||
| `nueva_orden` | Alta de una orden |
|
||||
| `orden` | Detalle: ítems, estados e ingreso de resultados |
|
||||
| `etiqueta` | Etiqueta imprimible para rotular la muestra |
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Endpoint | Qué hace |
|
||||
|---|---|
|
||||
| `get_ordenes.php` | Lista con filtros |
|
||||
| `get_orden.php` | Detalle de una orden |
|
||||
| `save_orden.php` | Crea o actualiza |
|
||||
| `save_resultado.php` | Guarda el resultado de un ítem |
|
||||
| `cambiar_estado_item.php` | Avanza el estado de un ítem individual |
|
||||
|
||||
Usan `api/_helpers.php` del módulo, con las mismas convenciones que el turnero.
|
||||
|
||||
## Flujo
|
||||
|
||||
```
|
||||
nueva_orden orden orden
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────┐ ┌───────────┐ ┌─────────────┐
|
||||
│ crear ├──────►│ muestra ├──────────►│ resultado │
|
||||
│ orden │ │ tomada │ │ ingresado │
|
||||
└─────────┘ └───────────┘ └─────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
etiqueta se rotula
|
||||
imprimible la muestra
|
||||
```
|
||||
|
||||
El estado se lleva **por ítem**, no por orden completa: una orden puede tener unos exámenes resueltos y otros pendientes.
|
||||
|
||||
## Relación con otros módulos
|
||||
|
||||
| Módulo | Vínculo |
|
||||
|---|---|
|
||||
| `lab_examenes` | De ahí sale el catálogo y los valores de referencia |
|
||||
| `lab_pacientes` | El paciente de la orden |
|
||||
| `medicos` | El médico que la solicitó |
|
||||
|
||||
## Al tocarlo
|
||||
|
||||
Los resultados de laboratorio son información clínica: un ítem mal guardado o un valor de referencia equivocado tienen consecuencias reales. Cualquier cambio en `save_resultado.php` merece probarse con una orden de prueba antes de subirlo.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Catálogos del laboratorio
|
||||
|
||||
Los módulos que administran las tablas maestras. Se agrupan acá porque comparten la misma forma: una pantalla de listado con alta, edición y baja sobre una tabla.
|
||||
|
||||
## Los módulos
|
||||
|
||||
| Módulo | Tabla principal | Qué administra |
|
||||
|---|---|---|
|
||||
| `lab_examenes` | `exam_tipos` | Catálogo de exámenes, valores de referencia y tarifas |
|
||||
| `medicos` | `medicos` | Médicos solicitantes |
|
||||
| `lab_pacientes` | `lab_pacientes` | Fichas clínicas e historial |
|
||||
| `lab_enfermeras` | `lab_enfermeras` | Personal clínico |
|
||||
| `lab_eps` | `lab_eps` | EPS y aseguradoras |
|
||||
| `lab_empresas` | `lab_empresas` | Empresas, convenios, subgrupos y tarifas |
|
||||
| `lab_ciudades` | `lab_ciudades` | Ciudades de pacientes |
|
||||
| `usuarios` | `admin_users`, `roles` | Usuarios y asignación de roles |
|
||||
|
||||
## Los que tienen endpoints propios
|
||||
|
||||
La mayoría son puentes al sistema anterior. Dos tienen código propio:
|
||||
|
||||
### `lab_examenes`
|
||||
|
||||
| Endpoint | Qué hace |
|
||||
|---|---|
|
||||
| `list.php` / `get.php` | Listado y detalle |
|
||||
| `save.php` | Alta y edición del examen |
|
||||
| `save_item.php` | Ítems que componen un examen |
|
||||
| `get_tarifas.php` / `save_tarifa.php` | Tarifas por empresa o convenio |
|
||||
|
||||
Es el catálogo del que dependen el turnero y el registro de exámenes. Un examen mal configurado se propaga a todo lo demás: consentimientos que no se piden, tarifas que no se aplican.
|
||||
|
||||
**`exam_tipo_consentimientos`** vincula un examen con los formularios que obliga a firmar. Es una de las dos fuentes de consentimientos del turnero; la otra es la estación destino.
|
||||
|
||||
### `medicos`
|
||||
|
||||
`list.php`, `save.php`, `delete.php`. El médico se asocia a la solicitud del turnero y sale impreso en los documentos.
|
||||
|
||||
## Pacientes
|
||||
|
||||
`lab_pacientes` es el más consultado de todos: lo usan el turnero, domicilios, registro de exámenes y el bot.
|
||||
|
||||
Campos que otros módulos dan por sentados:
|
||||
|
||||
| Campo | Quién lo usa |
|
||||
|---|---|
|
||||
| `numero_documento` | Búsqueda en todas las pantallas |
|
||||
| `telefono` | Envío de consentimientos y encuestas |
|
||||
| `nombre_completo`, `tipo_documento` | Encabezado de todos los documentos |
|
||||
| `fecha_nacimiento` | Cálculo de edad en formularios |
|
||||
| `eps` | Facturación |
|
||||
|
||||
Un teléfono mal cargado se manifiesta lejos de donde se originó: como un consentimiento que nunca llegó.
|
||||
|
||||
## Usuarios
|
||||
|
||||
Ver [Roles y permisos](?m=soporte&v=documentacion&s=arquitectura&d=roles-y-permisos) para el detalle del control de acceso.
|
||||
|
||||
Lo esencial al crear o editar un usuario:
|
||||
|
||||
- **`role` y `role_id` deben cambiarse juntos.** La interfaz lee uno, los permisos salen del otro.
|
||||
- **Cargá la cédula.** Es lo que aparece bajo la firma en los formularios.
|
||||
- El usuario debe **volver a iniciar sesión** para que un cambio de permisos surta efecto.
|
||||
|
||||
## Al agregar un catálogo nuevo
|
||||
|
||||
Si es un ABM simple, seguí el patrón de `medicos`: un `views/index.php` y tres endpoints (`list`, `save`, `delete`). Registralo en `SYSTEM_MODULES` y concedelo a los roles que corresponda, o nadie lo verá.
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* GET ?q= — Busca diagnósticos CIE-10 por código o descripción.
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireMethod('GET');
|
||||
requireTurnero();
|
||||
|
||||
Reference in New Issue
Block a user