El análisis de completitud cruzando roles contra módulos y tablas contra documentos encontró dos huecos reales. Manual de domicilios: recepcionista, lab_recepcion y lab_readonly tienen acceso a la pantalla administrativa de domicilios, y la única página sobre el tema era la del portal del enfermero, restringida a enfermeros. Son pantallas distintas —una ve todo, la otra solo lo propio— y ahora cada una tiene su guía. Los enfermeros pasan también a ver el manual de formularios, que su rol habilita. Menús y respuestas automáticas del bot: había cuatro tablas en uso que ninguna página explicaba. El bot responde solo las preguntas frecuentes mediante autoresponses (7 configuradas) y ofrece un menú interactivo de 21 opciones en dos niveles, todo configurable desde la base sin desplegar código. También quedan documentados el estado de conversación, los envíos masivos y las encuestas. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
97 lines
3.5 KiB
Markdown
97 lines
3.5 KiB
Markdown
# WhatsApp y bot
|
|
|
|
El sistema nació como bot de WhatsApp y esa integración sigue siendo central.
|
|
|
|
## Servicios
|
|
|
|
{{servicios}}
|
|
|
|
## `WhatsAppService`
|
|
|
|
Envuelve la Cloud API de Meta. Se elige la línea al construirlo:
|
|
|
|
```php
|
|
$wa = new WhatsAppService(); // principal
|
|
$wa = new WhatsAppService('turnero'); // turnero
|
|
```
|
|
|
|
Ambas líneas comparten cuenta (WABA) y token; **lo único que cambia es el `phone_number_id`**. Si un mensaje sale por la línea equivocada, casi siempre falta el argumento.
|
|
|
|
Métodos principales:
|
|
|
|
```php
|
|
$wa->sendTextMessage($telefono, $texto, $meta);
|
|
$wa->sendTemplateMessage($telefono, $plantilla, $idioma, [], [], $componentes, $meta);
|
|
```
|
|
|
|
`$meta` acompaña el registro del mensaje: `['canal' => 'turnero', 'operator_id' => adminId()]`.
|
|
|
|
## Plantillas
|
|
|
|
Fuera de la ventana de 24 horas hay que usar plantilla aprobada. `message_templates` guarda una copia local con sus `components`, pero **la copia no manda**: la versión real vive en Meta.
|
|
|
|
Consecuencia importante:
|
|
|
|
> Las URL de los botones están **en la plantilla**, no en el código. Nuestro código solo envía los parámetros (`{{1}}`). Cambiar el código no altera el enlace que recibe el paciente.
|
|
|
|
Ejemplo — botón de `consentimiento_turno_v2`:
|
|
|
|
```
|
|
https://erp.laboratorioximenacaicedo.com/form_cliente.php?t={{1}}
|
|
```
|
|
|
|
Y así se arman los componentes al enviar:
|
|
|
|
```php
|
|
$rawComps = [
|
|
['type' => 'body', 'parameters' => [['type' => 'text', 'text' => $codigo]]],
|
|
['type' => 'button', 'sub_type' => 'url', 'index' => '0',
|
|
'parameters' => [['type' => 'text', 'text' => $token]]],
|
|
];
|
|
```
|
|
|
|
### Respaldo
|
|
|
|
Si el envío por plantilla falla, se manda un texto plano con el enlace armado desde el dominio del servidor. Ese texto **no** pasa por Meta, así que su URL puede diferir de la del botón.
|
|
|
|
## Contenido configurable
|
|
|
|
Buena parte de lo que responde el bot vive en la base, no en el código: respuestas
|
|
automáticas por palabra clave y menús interactivos. Ver
|
|
[Menús y respuestas automáticas](?m=soporte&v=documentacion&s=tecnica&d=bot-menus-y-respuestas).
|
|
|
|
## `BotService`
|
|
|
|
Decide qué hacer con cada mensaje entrante:
|
|
|
|
1. ¿Aceptó los términos? Si no, se los pide y no avanza.
|
|
2. ¿Está en horario? (`BusinessHoursService`)
|
|
3. ¿La conversación la tomó un operador humano? El bot no interrumpe.
|
|
4. Si no, responde según el estado de la conversación (`ConversationStateService`) y el menú (`MenuService`).
|
|
|
|
## Términos y condiciones
|
|
|
|
| Tabla | Contenido |
|
|
|---|---|
|
|
| `terms_versions` | Versión activa, URL del documento, mensajes |
|
|
| `terms_acceptance` | Historial de aceptaciones |
|
|
| `system_config.terms_message` | Texto de bienvenida, **repite la URL dentro** |
|
|
|
|
Se vuelve a pedir la aceptación si nunca aceptó, si pasaron más de 6 meses, o si hay versión nueva con `forzar_reenvio`.
|
|
|
|
> La URL del documento está en **dos** lugares. Cambiar solo uno deja al otro sirviendo un enlace viejo.
|
|
|
|
## Configuración
|
|
|
|
Todo en `system_config`: `whatsapp_token`, `whatsapp_api_url`, `whatsapp_business_account_id`, `whatsapp_phone_number_id`, `whatsapp_phone_number_id_turnero`, `webhook_verify_token`.
|
|
|
|
## Diagnóstico
|
|
|
|
| Síntoma | Dónde mirar |
|
|
|---|---|
|
|
| Sale por el número equivocado | Falta `'turnero'` en el constructor |
|
|
| Enlace roto en un botón | La plantilla en Meta |
|
|
| No llega ninguna plantilla | Estado de aprobación en WhatsApp Manager |
|
|
| Llega texto plano en vez de plantilla | El respaldo actuó: la plantilla falló |
|
|
| El bot no responde | `webhook_logs`, horario, estado de la conversación |
|