Files
whatsapp/modules/soporte/docs/tecnica/30-formularios.md
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

4.3 KiB

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:

[
  {"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:

{"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.