30 Commits
Author SHA1 Message Date
Lizandro GuarnizoandClaude Opus 5 26025a6399 Reconocer por BSUID a quien oculta su teléfono, y poder pedírselo
Meta no permite averiguar el teléfono a partir del BSUID: no hay endpoint de
consulta inversa, cada empresa debe llevar su propia equivalencia. Pero el
BSUID llega en TODOS los webhooks de mensaje, también en los que aún traen
teléfono, así que la equivalencia se puede ir guardando sola mientras la
persona todavía muestra su número.

- users.bsuid guarda esa equivalencia, y el webhook la anota en cada mensaje.
  Cuando alguien oculte su número, se le seguirá reconociendo y respondiendo
  a su teléfono de siempre.
- Va en columna aparte y no en phone_number porque el teléfono además cruza
  con el paciente y el turnero; mezclarlos rompería esos cruces.
- Para quien nunca escribió mostrando el número queda pedirle el contacto:
  pedirContacto() manda el botón request_contact_info, y el webhook atiende
  el mensaje `contacts` que llega si acepta.
- Al vincular puede aparecer un segundo registro de la misma persona. No se
  fusionan: una fusión mal hecha mezcla dos historias clínicas. Gana el que
  tiene el teléfono, el otro queda anotado en el log para revisarlo a mano.
- scripts/backfill_bsuid.php carga las equivalencias del histórico (6.423),
  con --simular para verlas sin escribir.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 20:07:52 -05:00
Lizandro GuarnizoandClaude Opus 5 92179af56a Atender a quien oculta su teléfono en WhatsApp (BSUID)
Meta desplegó los nombres de usuario: quien oculta su teléfono llega al
webhook sin `from` ni `wa_id`, identificado solo por su BSUID con la forma
"CO.1761088155094242". El webhook exigía teléfono y descartaba el mensaje
en silencio, sin guardarlo ni dejar rastro: 221 mensajes de 65 personas
ignorados por completo, ya el 3-6% de lo que entra cada día y subiendo.

- webhook.php lee `from_user_id` cuando no llega el teléfono, y rescata el
  nombre del contacto indexando también por `user_id`.
- WhatsAppService responde por BSUID: Meta exige el campo `recipient` en
  lugar de `to`. Se traduce en sendMessage(), el punto por donde pasan todos
  los envíos, en vez de en los diez métodos que arman payloads.
- formatPhoneNumber() devuelve el BSUID intacto; antes le quitaba el punto
  y las letras y lo dejaba en un destinatario inexistente.
- Las cuatro columnas del flujo pasan a varchar(32): los BSUID de Meta
  llegan a 23 caracteres y se truncaban en silencio en varchar(20).

De estas personas no tendremos el teléfono; si un flujo lo necesita, hay
que identificarlas por documento.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:41:10 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 03f02d2788 fix(webhook): skip SSE notification and DB notification for canal=turnero messages
Turnero messages were triggering the SSE event that conversations.php listens to,
causing the contact to flash briefly at the top of the list before disappearing
on the next poll (since get_conversations.php filters them out by canal).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:43:20 -05:00
Lizandro GuarnizoandClaude Sonnet 4.6 5acd46df5a fix(turnero): route incoming messages by phone_number_id and fix WhatsAppService canal
- WhatsAppService($canal): when 'turnero', swaps phoneNumberId to whatsapp_phone_number_id_turnero
  so outgoing messages actually go from the turnero number (not the main bot)
- webhook.php: reads metadata.phone_number_id from the payload and compares it to
  whatsapp_phone_number_id_turnero; if it matches, saves canal='turnero' and skips bot processing
- Previously all incoming messages had canal=NULL/bot so Chat Turnero never saw them,
  and all outgoing messages from Chat Turnero were sent via the wrong (main bot) number

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 08:26:11 -05:00
Lizandro Guarnizo bcfaf62293 fix: deduplicar webhooks duplicados con INSERT IGNORE + UNIQUE index en message_id
- conversations.message_id ahora tiene UNIQUE index (aplicado en BD prod)
- saveMessage() usa INSERT IGNORE: si el mismo wamid llega dos veces en
  paralelo solo una llamada procesa el mensaje y llama al bot
- La segunda llamada recibe rowCount=0 y hace continue sin pasar al bot
- Elimina race condition que enviaba bienvenida + términos simultáneamente
2026-03-13 19:22:34 -05:00
Lizandro Guarnizo 237f4aea0f Update webhook.php 2026-02-21 10:19:10 -05:00
Lizandro Guarnizo de4b07c806 up 2026-02-21 07:37:36 -05:00
Lizandro Guarnizo 602e6d3724 up 2026-02-20 11:21:06 -05:00
Lizandro Guarnizo c965135af9 up 2026-02-20 11:01:33 -05:00
Lizandro Guarnizo 421a5a4d7c up 2026-02-20 09:07:37 -05:00
Lizandro Guarnizo 1f224044f7 up 2026-01-27 14:51:41 -05:00
Lizandro Guarnizo 83132ff0d5 Revert "up"
This reverts commit 269dc6bed1.
2026-01-27 01:04:32 -05:00
Lizandro Guarnizo 269dc6bed1 up 2026-01-27 00:52:36 -05:00
Lizandro Guarnizo e2c8fc994a up 2026-01-25 21:48:56 -05:00
Lizandro Guarnizo ac6d04c31d up 2026-01-24 01:17:22 -05:00
lizandrogd b709d65190 u 2026-01-21 15:19:58 -05:00
lizandrogd 3f6e723fac up 2026-01-21 12:33:11 -05:00
lizandrogd 901d51c82f up 2026-01-21 12:20:46 -05:00
lizandrogd c7d0b8b70c up 2026-01-21 11:58:17 -05:00
lizandrogd 5727721f02 up 2026-01-21 11:04:41 -05:00
lizandrogd 5e9220590a up 2026-01-21 10:57:02 -05:00
lizandrogd fd9c718a44 up 2026-01-21 09:29:59 -05:00
lizandrogd 45a11032f5 mejoras 2026-01-21 08:28:54 -05:00
lizandrogd cec91ff45a up 2026-01-21 02:49:42 -05:00
lizandrogd edfa5f68d9 up 2026-01-21 02:34:23 -05:00
lizandrogd b1961f0116 up 2026-01-21 02:22:29 -05:00
lizandrogd 87b89b52a5 up 2026-01-21 01:02:17 -05:00
lizandrogd 4e3e02111b up 2026-01-20 23:55:00 -05:00
lizandrogd 648a6c0291 up 2026-01-20 22:13:02 -05:00
lizandrogd ce12ac2cce w 2025-11-18 20:26:36 -05:00