From dea9dc4401889ec38048412ae015a441b21b946e Mon Sep 17 00:00:00 2001 From: Gustavo Date: Fri, 14 Aug 2026 12:31:20 -0300 Subject: [PATCH] fix: corrige achados da revisao final (DDI idempotente, mascara DDI 12/13 digitos, status DV, validacao no load, autofill dispara mascaras) Endereca 5 achados da revisao final de branch: - Important #1: normalizar_telefone_com_ddi agora e idempotente (nao duplica 55 independente do tamanho) - Important #2: mascara de telefone detecta DDI colado por tamanho total (12/13 digitos), nao mais so pelo campo especifico - Minor #3: buscarCnpj pula lookup na Receita quando DV do CNPJ e invalido, preservando a mensagem de erro - Minor #4: detectarEValidarDocumento roda uma vez no carregamento da pagina - Minor #5: autofill da Receita dispara evento input para acionar as mascaras de UF/CEP/TELEFONE Co-Authored-By: Claude Sonnet 5 --- app/normalize.py | 10 ++++++---- app/templates/cliente_form.html | 10 +++++++--- tests/test_normalize.py | 9 +++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/app/normalize.py b/app/normalize.py index fff2b61..2c80fd4 100644 --- a/app/normalize.py +++ b/app/normalize.py @@ -56,14 +56,16 @@ def normalizar_telefone_com_ddi(bruto: str | None) -> str: gravados sempre com DDI, mesmo que o usuário não digite (mesmo padrão que CLIENTE_CONTATO.TELEFONE já usa para envio de WhatsApp). - Um valor de 12-13 dígitos começando com "55" é tratado como já tendo - DDI (não duplica). Qualquer outro tamanho não vazio recebe "55" na - frente. Vazio continua vazio (campo não obrigatório). + Um valor que já começa com "55" é tratado como já tendo DDI (não + duplica), independente do tamanho — garante idempotência mesmo em + round-trips (ex.: reenvio do formulário já normalizado). Qualquer + outro valor não vazio recebe "55" na frente. Vazio continua vazio + (campo não obrigatório). """ digitos = normalizar_telefone(bruto) if not digitos: return "" - if digitos.startswith("55") and len(digitos) in (12, 13): + if digitos.startswith("55"): return digitos return "55" + digitos diff --git a/app/templates/cliente_form.html b/app/templates/cliente_form.html index aa4ac73..e291d0f 100644 --- a/app/templates/cliente_form.html +++ b/app/templates/cliente_form.html @@ -125,13 +125,15 @@ } $cnpj.addEventListener('input', detectarEValidarDocumento); + detectarEValidarDocumento(); function aplicarMascaraTelefone(elemento, digitosAposDdd) { elemento.addEventListener('input', function () { var digitos = elemento.value.replace(/\D/g, ''); - // Se veio com DDI 55 colado (12-13 dígitos totais), usa só o resto. - var totalComDdi = 2 + digitosAposDdd; // DDI(2) + DDD(2) já contado em digitosAposDdd - if (digitos.length >= totalComDdi && digitos.slice(0, 2) === '55') { + // DDI 55 colado: detecta por tamanho total (12 ou 13 dígitos), não + // pelo tamanho esperado do campo específico — um número de 12 + // dígitos colado no campo de celular ainda deve ter o 55 removido. + if ((digitos.length === 12 || digitos.length === 13) && digitos.slice(0, 2) === '55') { digitos = digitos.slice(2); } digitos = digitos.slice(0, digitosAposDdd); @@ -181,6 +183,7 @@ async function buscarCnpj() { var limpo = normalizarCnpj($cnpj.value); if (limpo.length !== 14) return; + if (limpo.length === 14 && !validarDvCnpj(limpo)) return; if ($status) $status.textContent = 'Buscando dados do CNPJ...'; @@ -196,6 +199,7 @@ var $input = document.getElementById(campo); if ($input && !$input.value && corpo.dados[campo]) { $input.value = corpo.dados[campo]; + $input.dispatchEvent(new Event('input')); preencheu = true; } }); diff --git a/tests/test_normalize.py b/tests/test_normalize.py index b7b6c0d..f27b00a 100644 --- a/tests/test_normalize.py +++ b/tests/test_normalize.py @@ -98,6 +98,15 @@ def test_normaliza_telefone_com_ddi_vazio_continua_vazio(): assert normalizar_telefone_com_ddi(None) == "" +def test_normaliza_telefone_com_ddi_e_idempotente(): + """Aplicar a função duas vezes seguidas nunca deve dobrar o DDI.""" + casos = ["(75) 3333-4444", "(75) 99909-1780", "5575999091780", "3333-4444", ""] + for bruto in casos: + uma_vez = normalizar_telefone_com_ddi(bruto) + duas_vezes = normalizar_telefone_com_ddi(uma_vez) + assert duas_vezes == uma_vez, f"não é idempotente para {bruto!r}: {uma_vez!r} -> {duas_vezes!r}" + + def test_normaliza_uf_maiusculas_e_trunca(): assert normalizar_uf("ba") == "BA" assert normalizar_uf(" sp ") == "SP"