Files
COMERCIAL-GTI/maquina-comercial-pessoal/src/phone.mjs
T
GustavoandClaude Sonnet 5 417da56bd6 chore: import maquina-comercial-pessoal history via subtree
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

git-subtree-dir: maquina-comercial-pessoal
git-subtree-mainline: f5af038e19
git-subtree-split: a9ef4d776d
2026-09-28 15:50:17 -03:00

92 lines
3.9 KiB
JavaScript

export function normalizePhone(value = '') {
return String(value).replace(/\D/g, '');
}
export function equivalentPhoneNumbers(value = '') {
const digits = normalizePhone(value);
const numbers = digits ? [digits] : [];
if (!digits.startsWith('55')) return numbers;
const prefix = digits.slice(0, 4);
const local = digits.slice(4);
if (local.length === 9 && local.startsWith('9')) numbers.push(`${prefix}${local.slice(1)}`);
if (local.length === 8 && /^[6-9]/.test(local)) numbers.push(`${prefix}9${local}`);
return [...new Set(numbers)];
}
// equivalentPhoneNumbers NAO e simetrica: ela so gera a variante de 8 digitos a
// partir de um celular de 9 digitos quando o local comeca com 6-9. Um numero
// como 557533334444 (local '33334444') nao volta para 5575933334444, embora o
// caminho inverso exista — o que fazia um lado do par ser bloqueado e o outro
// nao, e escondia o grupo da tela de revisao.
//
// canonicalPhoneKey resolve isso reduzindo SEMPRE o celular brasileiro de 13
// digitos com nono digito para a forma de 12 digitos (mesma regra de remocao ja
// usada por equivalentPhoneNumbers). Dois numeros pertencem a mesma linha
// quando compartilham a chave canonica — uma relacao simetrica por construcao.
export function canonicalPhoneKey(value = '') {
const digits = normalizePhone(value);
if (!digits.startsWith('55')) return digits;
const prefix = digits.slice(0, 4);
const local = digits.slice(4);
if (local.length === 9 && local.startsWith('9')) return `${prefix}${local.slice(1)}`;
return digits;
}
// Todas as formas que um numero pode ter armazenado e que reduzem a mesma chave
// canonica. O numero informado vem sempre primeiro (o override guarda esse
// valor). Usado para casar contra a coluna crua `leads.whatsapp`.
export function canonicalPhoneVariants(value = '') {
const digits = normalizePhone(value);
if (!digits) return [];
const key = canonicalPhoneKey(digits);
const variants = new Set([digits, key]);
if (key.startsWith('55') && key.length === 12) {
variants.add(`${key.slice(0, 4)}9${key.slice(4)}`);
}
return [...variants];
}
// Fragmentos SQL equivalentes as funcoes JS acima. Ficam neste modulo para que
// exista uma unica origem da regra 8/9 digitos — tests/phone.test.mjs prova que
// as duas implementacoes concordam.
export function normalizedSql(column) {
return `replace(replace(replace(replace(replace(${column}, '+', ''), ' ', ''), '-', ''), '(', ''), ')', '')`;
}
// Espelha equivalentPhoneNumbers: alterna entre as duas variantes brasileiras.
export function equivalentSql(column) {
const number = normalizedSql(column);
return `CASE
WHEN substr(${number}, 1, 2) = '55' AND length(${number}) = 13 AND substr(${number}, 5, 1) = '9'
THEN substr(${number}, 1, 4) || substr(${number}, 6)
WHEN substr(${number}, 1, 2) = '55' AND length(${number}) = 12 AND substr(${number}, 5, 1) BETWEEN '6' AND '9'
THEN substr(${number}, 1, 4) || '9' || substr(${number}, 5)
ELSE ${number}
END`;
}
// Espelha canonicalPhoneKey.
export function canonicalKeySql(column) {
const number = normalizedSql(column);
return `CASE
WHEN substr(${number}, 1, 2) = '55' AND length(${number}) = 13 AND substr(${number}, 5, 1) = '9'
THEN substr(${number}, 1, 4) || substr(${number}, 6)
ELSE ${number}
END`;
}
// A outra forma da mesma chave canonica (a de 13 digitos). Junto com
// canonicalKeySql cobre as duas formas possiveis de armazenamento, permitindo
// `outra.whatsapp IN (chave, variante)` — comparacao contra a coluna crua, que
// mantem o uso de idx_leads_whatsapp.
export function canonicalVariantSql(column) {
const number = normalizedSql(column);
return `CASE
WHEN substr(${number}, 1, 2) = '55' AND length(${number}) = 13 AND substr(${number}, 5, 1) = '9'
THEN ${number}
WHEN substr(${number}, 1, 2) = '55' AND length(${number}) = 12
THEN substr(${number}, 1, 4) || '9' || substr(${number}, 5)
ELSE ${number}
END`;
}