Files
whatsapp/modules/soporte/docs/tecnica/30-formularios.md
T
Lizandro GuarnizoandClaude Opus 5 32c209710c Documentación completa del proyecto en el módulo Soporte
21 documentos en cuatro secciones, escritos sobre el comportamiento real del
sistema —incluidos los casos que costaron diagnosticar esta semana.

Manual de usuario (visible para todos): primeros pasos, recepción, toma de
muestras, portal del enfermero y administración. Orientado a tareas concretas,
no a describir pantallas.

Documentación técnica: índice de módulos, turnero, formularios y firma digital,
WhatsApp y bot, domicilios, webhook (migrado de WEBHOOK_ENDPOINTS.md) e
inventario de endpoints.

Arquitectura: visión general, enrutamiento y registro de módulos, roles y
permisos, modelo de datos, integración con WhatsApp, y decisiones tomadas con
su deuda técnica asociada.

Operación: runbook de incidentes ordenado por síntoma, configuraciones críticas
—incluido qué vive en Meta y no en la base— y despliegue.

Se documentan explícitamente las trampas conocidas: role/role_id que hay que
mantener sincronizados, las columnas can_* que el control de acceso no lee, las
URL de plantilla que no se cambian desde el código, y las columnas históricas
que quedaron en NULL sin forma de recuperarlas.

README_DOCS.md apunta al módulo y explica cómo agregar páginas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 10:14:32 -05:00

105 lines
4.3 KiB
Markdown

# Formularios y firma digital
Cómo se definen los formularios, cómo se envían y cómo se firman. Es transversal: lo usan el turnero, los domicilios y los envíos sueltos.
## Definición
Un formulario es una fila en `lab_formularios`. Su estructura está en la columna `esquema`, un JSON con la lista de campos:
```json
[
{"id": "_sep1", "tipo": "separador", "label": "Datos del paciente"},
{"id": "_nom", "tipo": "linked", "linked_key": "nombre_completo", "label": "Nombre"},
{"id": "_sint", "tipo": "checkbox", "label": "Síntomas", "options": ["Fiebre", "Tos"]},
{"id": "_fir", "tipo": "firma_profesional", "label": "Firma del profesional"}
]
```
### Tipos de campo
| Tipo | Qué es |
|---|---|
| `separador` | Encabezado de sección; admite `condicion` |
| `parrafo` | Texto fijo (consentimientos, notas legales) |
| `texto`, `textarea`, `numero` | Entrada libre |
| `fecha`, `fecha_hoy`, `hora` | Fechas y horas |
| `radio`, `checkbox`, `select` | Opciones |
| `linked` | Se autocompleta con un dato del paciente vía `linked_key` |
| `firma` | Firma del paciente |
| `firma_profesional` | Firma del profesional |
### Secciones condicionales
Un separador puede depender de otro campo:
```json
{"id": "_sep_ins", "tipo": "separador", "label": "Insulina · Minuto 0",
"condicion": {"campo_id": "_examen", "valores": ["Insulina"]}}
```
La sección y **todos sus campos** se ocultan si la condición no se cumple. Los campos heredan el estado mediante el atributo `data-sep-id`.
## Las dos vías de envío
Un mismo formulario se firma por dos caminos, con tablas y tokens distintos:
| Vía | Tabla | Token | Respuestas |
|---|---|---|---|
| Turnero | `turnero_consentimientos` | UUID → `?token=` | `datos_respuestas` |
| Domicilios y envíos | `lab_form_envios` | 64 hex → `?t=` | `datos_cliente` |
Las dos las muestra `ver_formulario_enviado.php`, que distingue **por el formato del token**. De ahí que existan dos parámetros para lo que parece lo mismo.
`form_cliente.php` detecta tokens con formato UUID y redirige a `ver_formulario_enviado.php` — necesario porque la plantilla de WhatsApp aprobada en Meta apunta a la primera página.
## Parámetros del visor
| Parámetro | Efecto |
|---|---|
| `token` | Consentimiento del turnero (UUID) |
| `t` | Envío de formulario (64 hex) |
| `id` | Acceso interno con sesión |
| `embed=1` | Modo embebido; **activa el filtrado de secciones** |
| `compact=1` | Grilla de campos y tarjetas de toma |
| `zoom` | Escala |
| `autoprint=1` | Abre el diálogo de impresión |
> `embed=1` no es cosmético: sin él no se aplica el filtrado de secciones de tomas prolongadas y el documento muestra secciones que no corresponden. Bandeja e historial lo pasan siempre.
## Firma
### Del paciente
Se dibuja en un canvas y se guarda como imagen en `datos_cliente['<campo>_svg']`. También se admite pad biométrico Topaz.
### Del profesional
Se dibuja igual, pero además queda **quién firmó**. Hay tres endpoints según el contexto:
| Endpoint | Contexto |
|---|---|
| `modules/turnero/api/guardar_toma.php` | Tomas prolongadas — una firma por toma |
| `modules/turnero/api/firmar_profesional_consentimiento.php` | Consentimientos del turnero |
| `api/lab/firmar_profesional.php` | Envíos de formularios |
La identidad se guarda como `_pro_nombre` y `_pro_cedula`; en tomas prolongadas, además por campo (`_tm30_f_pro_nombre`), porque cada toma puede firmarla alguien distinto.
De dónde sale la identidad:
```
admin_users.cedula → personal en general
lab_enfermeras.numero_documento → enfermeros (vía admin_users.enfermera_id)
```
> Al mostrar un documento firmado **no se usa un valor por defecto**: si no quedó guardado quién firmó, se muestra vacío. Antes se caía al usuario de la sesión actual, lo que atribuía la firma a quien simplemente estaba mirando el documento.
## Precarga desde una visita anterior
`modules/turnero/api/get_formulario_anterior.php` devuelve las respuestas del último formulario firmado del mismo paciente, para no reescribir la historia clínica en cada visita.
Excluye deliberadamente firmas e identidad del profesional anterior: cada visita se firma de nuevo, con la fecha de hoy y quien atienda.
## Diseñador
`lab_formulario_builder.php` permite armar el esquema desde la interfaz, sin escribir JSON a mano.