/** * Normaliza un teléfono a E.164 (`+` seguido de 8 a 15 dígitos). * * Es la clave de identidad de la clienta: sin ella, el mismo número tecleado de * dos formas produce dos fichas, y la auditoría del spa midió que el teléfono es * el único campo con cobertura suficiente para reconciliar canales. * * Devuelve `null` cuando no se puede normalizar con certeza. `null` no es un * error: significa "clienta no contactable", que es un estado legítimo y medido * (40.8 % del histórico). Nunca se inventa un país para rellenarlo. */ export function normalizePhone( raw: string | null | undefined, defaultCountry = "52" ): string | null { if (raw == null) return null; const trimmed = String(raw).trim(); if (!trimmed) return null; // Una letra en el campo significa texto libre ("no tengo", "el de su mamá"), // no un teléfono mal escrito. No se intenta rescatar. if (/[a-zA-Z]/.test(trimmed)) return null; const explicitIntl = trimmed.startsWith("+") || /^00\d/.test(trimmed); let digits = trimmed.replace(/\D/g, ""); if (trimmed.startsWith("00")) digits = digits.slice(2); if (!digits) return null; if (!explicitIntl) { // "01" es el prefijo mexicano de larga distancia y se quita como unidad, no // como "ceros a la izquierda": si solo se quitara el 0, el 1 restante se // confundiría con el código de país de Estados Unidos. if (digits.length === 12 && digits.startsWith("01")) { digits = digits.slice(2); } else { digits = digits.replace(/^0+/, ""); } } // "52 1 XXXXXXXXXX": el 1 de móvil que WhatsApp sigue arrastrando. if (digits.length === 13 && digits.startsWith(`${defaultCountry}1`)) { digits = defaultCountry + digits.slice(3); } // Diez dígitos sueltos = número nacional. if (!explicitIntl && digits.length === 10) { digits = defaultCountry + digits; } if (digits.length < 8 || digits.length > 15) return null; return `+${digits}`; }