Evitar teléfonos falsos en la historia clínica, y pedir el número a quien lo oculta

El arreglo anterior dejó un defecto: obtenerOCrearDesdeWhatsapp() copiaba
users.phone_number al teléfono de la ficha, y para quien oculta su número ahí
va el BSUID. normalizarTelefono() le quitaba el punto y las letras, así que
"CO.1761088155094242" quedaba guardado como "1761088155094242": un número de
16 dígitos, falso, con apariencia de real, dentro de una historia clínica y
sin que nadie lo notara. Ahora esa ficha se crea sin teléfono, que es la
verdad: no lo tenemos.

- esBsuid() queda definido una sola vez, en config.php, que es donde lo ven
  tanto el servicio de WhatsApp como las clases del laboratorio.
- La lista y el detalle de pacientes dicen "Solo por WhatsApp" en vez de
  mostrar el identificador crudo: recepción necesita entender por qué no
  puede llamar, no ver un código.
- Al crear la ficha desde una conversación se le pide el número con el botón
  de Meta, una sola vez (users.contacto_pedido_at). El texto es editable
  desde configuración. Solo se marca como pedido si Meta aceptó el envío,
  para poder reintentar si falló.
- tests/test_bsuid.php: 30 verificaciones sobre identidad, envío, vinculación
  y creación de fichas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-08-11 20:26:31 -05:00
co-authored by Claude Opus 5
parent 26025a6399
commit 2b1f08b03f
6 changed files with 157 additions and 8 deletions
+35 -3
View File
@@ -472,6 +472,28 @@ function fmtFecha(str) {
return str.slice(0, 10).split('-').reverse().join('/');
}
// Quien oculta su número en WhatsApp llega identificado con un BSUID
// ("CO.1761088155094242"), que se guarda en phone_number pero no es un teléfono.
const esBsuid = v => /^[A-Z]{2}\.\d+$/.test(String(v || ''));
/**
* Celda de contacto. Si de esta persona no tenemos teléfono porque lo tiene
* oculto, se dice así en vez de mostrar el identificador crudo: recepción
* necesita entender por qué no puede llamarla, no ver un código.
*/
function celdaTelefono(p) {
if (esBsuid(p.phone_number)) {
return (p.telefono ? esc(p.telefono) : '<span class="text-muted">Sin teléfono</span>')
+ '<br><i class="fab fa-whatsapp text-success"></i> '
+ '<small class="text-muted" title="Tiene el número oculto en WhatsApp. '
+ 'Se le puede escribir por el chat, pero no llamar.">Solo por WhatsApp</small>';
}
return esc(p.telefono || '—')
+ (p.phone_number
? `<br><i class="fab fa-whatsapp text-success"></i> <small class="text-muted">${esc(p.phone_number)}</small>`
: '');
}
async function cargarLista(pag = 1) {
paginaActual = pag;
const busq = document.getElementById('buscador').value.trim();
@@ -495,7 +517,7 @@ async function cargarLista(pag = 1) {
${p.genero ? `<small class="text-muted">${p.genero==='M'?'Masculino':p.genero==='F'?'Femenino':'Otro'}</small>` : ''}
</td>
<td class="small">${tipoDocLabel(p.tipo_documento)}<br><span class="fw-semibold">${esc(p.numero_documento||'—')}</span></td>
<td class="small">${esc(p.telefono||'—')}${p.phone_number ? `<br><i class="fab fa-whatsapp text-success"></i> <small class="text-muted">${esc(p.phone_number)}</small>` : ''}</td>
<td class="small">${celdaTelefono(p)}</td>
<td class="small text-muted">${esc(p.email||'—')}</td>
<td class="small text-muted">${esc(p.ciudad||'—')}</td>
<td class="small text-muted">${esc(p.eps||'—')}</td>
@@ -546,8 +568,18 @@ async function verDetalle(id) {
document.getElementById('detail-body').innerHTML = `
<dl class="row small mb-3">
<dt class="col-5 text-muted">Documento</dt><dd class="col-7">${tipoDocLabel(p.tipo_documento)} ${esc(p.numero_documento||'—')}</dd>
<dt class="col-5 text-muted">Teléfono</dt><dd class="col-7">${esc(p.telefono||'—')}</dd>
<dt class="col-5 text-muted">WhatsApp</dt><dd class="col-7">${p.phone_number ? `<i class="fab fa-whatsapp text-success"></i> ${esc(p.phone_number)}` : '—'}</dd>
<dt class="col-5 text-muted">Teléfono</dt><dd class="col-7">${
p.telefono ? esc(p.telefono)
: (esBsuid(p.phone_number)
? '<span class="text-muted">Sin teléfono — lo tiene oculto en WhatsApp</span>'
: '—')
}</dd>
<dt class="col-5 text-muted">WhatsApp</dt><dd class="col-7">${
!p.phone_number ? '—'
: (esBsuid(p.phone_number)
? '<i class="fab fa-whatsapp text-success"></i> Se le puede escribir por el chat, pero no llamar'
: `<i class="fab fa-whatsapp text-success"></i> ${esc(p.phone_number)}`)
}</dd>
<dt class="col-5 text-muted">Origen</dt><dd class="col-7">${origenBadge(p.origen)}</dd>
<dt class="col-5 text-muted">Registro</dt><dd class="col-7 text-muted small">${fmtFecha(p.created_at)}</dd>
${p.email ? `<dt class="col-5 text-muted">Email</dt><dd class="col-7">${esc(p.email)}</dd>` : ''}