feat: validação de CNPJ e máscaras de telefone/UF/CEP no formulário de cliente
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
59f15d9ac0
commit
eec7ce21b5
@@ -51,7 +51,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<p><small>* campos obrigatórios. Os demais podem ficar em branco — implantação/mensalidade/juros ficam 0,00 e as datas de contrato ficam com a data de hoje até serem ajustadas.</small></p>
|
<p><small>* campos obrigatórios. Os demais podem ficar em branco — implantação/mensalidade/juros ficam 0,00 e as datas de contrato ficam com a data de hoje até serem ajustadas.</small></p>
|
||||||
<button type="submit">Salvar</button>
|
<button type="submit" id="botao-salvar">Salvar</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -65,6 +65,113 @@
|
|||||||
var $status = document.getElementById('cnpj-status');
|
var $status = document.getElementById('cnpj-status');
|
||||||
if (!$cnpj) return;
|
if (!$cnpj) return;
|
||||||
|
|
||||||
|
var $botaoSalvar = document.getElementById('botao-salvar');
|
||||||
|
|
||||||
|
// Mesma fórmula de dígito verificador de app/normalize.py
|
||||||
|
// (_digito_verificador + validar_dv_cnpj) — módulo 11 sobre valor ASCII
|
||||||
|
// − 48 de cada caractere, suporta CNPJ numérico e o alfanumérico
|
||||||
|
// vigente desde 31/07/2026.
|
||||||
|
var PESOS_CNPJ_DV1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
||||||
|
var PESOS_CNPJ_DV2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
||||||
|
|
||||||
|
function digitoVerificador(valores, pesos) {
|
||||||
|
var soma = 0;
|
||||||
|
for (var i = 0; i < valores.length; i++) soma += valores[i] * pesos[i];
|
||||||
|
var resto = soma % 11;
|
||||||
|
return resto < 2 ? 0 : 11 - resto;
|
||||||
|
}
|
||||||
|
|
||||||
|
function valorCaractere(c) {
|
||||||
|
return c.charCodeAt(0) - 48;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validarDvCnpj(cnpj14) {
|
||||||
|
var base = [];
|
||||||
|
for (var i = 0; i < 12; i++) base.push(valorCaractere(cnpj14[i]));
|
||||||
|
var dvInformado = [parseInt(cnpj14[12], 10), parseInt(cnpj14[13], 10)];
|
||||||
|
var dv1 = digitoVerificador(base, PESOS_CNPJ_DV1);
|
||||||
|
var dv2 = digitoVerificador(base.concat([dv1]), PESOS_CNPJ_DV2);
|
||||||
|
return dvInformado[0] === dv1 && dvInformado[1] === dv2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectarEValidarDocumento() {
|
||||||
|
var limpo = normalizarCnpj($cnpj.value);
|
||||||
|
if ($botaoSalvar) $botaoSalvar.disabled = false;
|
||||||
|
|
||||||
|
if (/^[0-9]{11}$/.test(limpo)) {
|
||||||
|
if ($status) {
|
||||||
|
$status.textContent = 'CPF detectado.';
|
||||||
|
$status.style.color = 'var(--cor-texto-secundario)';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (/^[0-9A-Z]{12}[0-9]{2}$/.test(limpo)) {
|
||||||
|
if (validarDvCnpj(limpo)) {
|
||||||
|
if ($status) {
|
||||||
|
$status.textContent = 'CNPJ detectado.';
|
||||||
|
$status.style.color = 'var(--cor-texto-secundario)';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($status) {
|
||||||
|
$status.textContent = 'CNPJ inválido (dígito verificador não confere).';
|
||||||
|
$status.style.color = 'var(--cor-perigo)';
|
||||||
|
}
|
||||||
|
if ($botaoSalvar) $botaoSalvar.disabled = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Tamanho ainda incompleto/indeterminado: não bloqueia, não rotula.
|
||||||
|
if ($status) $status.textContent = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$cnpj.addEventListener('input', 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') {
|
||||||
|
digitos = digitos.slice(2);
|
||||||
|
}
|
||||||
|
digitos = digitos.slice(0, digitosAposDdd);
|
||||||
|
|
||||||
|
var ddd = digitos.slice(0, 2);
|
||||||
|
var resto = digitos.slice(2);
|
||||||
|
var meio = resto.slice(0, digitosAposDdd - 6);
|
||||||
|
var fim = resto.slice(digitosAposDdd - 6);
|
||||||
|
|
||||||
|
var formatado = '';
|
||||||
|
if (ddd) formatado += '(' + ddd;
|
||||||
|
if (ddd.length === 2) formatado += ') ';
|
||||||
|
formatado += meio;
|
||||||
|
if (fim) formatado += '-' + fim;
|
||||||
|
elemento.value = formatado;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var $telefone = document.getElementById('TELEFONE');
|
||||||
|
var $celular = document.getElementById('CELULAR');
|
||||||
|
// TELEFONE: DDD(2) + 8 dígitos = 10 dígitos após o DDI.
|
||||||
|
if ($telefone) aplicarMascaraTelefone($telefone, 10);
|
||||||
|
// CELULAR: DDD(2) + 9 dígitos (com o 9 na frente) = 11 dígitos após o DDI.
|
||||||
|
if ($celular) aplicarMascaraTelefone($celular, 11);
|
||||||
|
|
||||||
|
var $uf = document.getElementById('UF');
|
||||||
|
if ($uf) {
|
||||||
|
$uf.addEventListener('input', function () {
|
||||||
|
$uf.value = $uf.value.toUpperCase().replace(/[^A-Z]/g, '').slice(0, 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var $cep = document.getElementById('CEP');
|
||||||
|
if ($cep) {
|
||||||
|
$cep.addEventListener('input', function () {
|
||||||
|
var digitos = $cep.value.replace(/\D/g, '').slice(0, 8);
|
||||||
|
$cep.value = digitos.length > 5 ? digitos.slice(0, 5) + '-' + digitos.slice(5) : digitos;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var CAMPOS_PARA_PREENCHER = ['RAZAO', 'FANTASIA', 'ENDERECO', 'CIDADE', 'BAIRRO', 'UF', 'CEP', 'TELEFONE', 'EMAIL'];
|
var CAMPOS_PARA_PREENCHER = ['RAZAO', 'FANTASIA', 'ENDERECO', 'CIDADE', 'BAIRRO', 'UF', 'CEP', 'TELEFONE', 'EMAIL'];
|
||||||
|
|
||||||
function normalizarCnpj(valor) {
|
function normalizarCnpj(valor) {
|
||||||
|
|||||||
Reference in New Issue
Block a user