Grupos exclusivos de desconto no WhatsApp — Faca parte agora! Participar

CNPJ alfanumérico no Magento 2: validar no checkout

Adapte o Magento 2 ao CNPJ alfanumérico: regra de validação JS via mixin do Magento_Ui no checkout e validação server-side com plugin em PHP.

CNPJ alfanumérico no Magento 2: validar no checkout

Adaptar o CNPJ alfanumérico no Magento 2 é simples quando você entende que o problema não está no Magento em si, mas na regra de validação numérica antiga que rejeita letras. Neste tutorial você vai trocar a validação do checkout por uma regra customizada (via mixin do Magento_Ui) e blindar o servidor com um plugin em PHP — usando a mesma fórmula de dígito verificador da Receita Federal.

O que muda no CNPJ alfanumérico

A partir de julho de 2026 (Instrução Normativa RFB nº 2.229/2024), o CNPJ mantém as 14 posições e a máscara XX.XXX.XXX/XXXX-DD, mas as 12 primeiras posições passam a aceitar letras maiúsculas A–Z além dos dígitos 0–9. Apenas os dois dígitos verificadores (posições 13–14) continuam numéricos. CNPJs numéricos atuais continuam válidos e convivem com os novos — seu Magento precisa aceitar os dois formatos.

Por que a validação numérica antiga rejeita letras

No checkout do Magento 2, o CNPJ normalmente chega pelo atributo taxvat (o campo vat_id do endereço) ou por um campo dedicado adicionado por módulos brasileiros — como Gabrielqs_MageBR, Amasty BR ou similares. Esses módulos costumam validar o CNPJ com uma regra de KnockoutJS que assume entrada só de dígitos: usam type="number", máscaras com \d e a fórmula clássica do módulo 11 multiplicando o caractere como número. Quando o cliente digita 12ABC34501DE, a letra A não passa pelo parseInt, a máscara descarta o caractere e a regra retorna inválido. A correção é registrar uma nova regra de validação e apontar o campo para ela.

Validando CNPJ alfanumérico em JavaScript

O Magento usa o validador Magento_Ui/js/lib/validation/validator, que expõe o método validator.addRule(nome, função, mensagem) para registrar regras customizadas. A função abaixo é a lógica golden, pronta para virar uma regra. Note os pesos fixos e o cálculo de cada caractere como charCodeAt(i) - 48.

JavaScript
// Valor de cada caractere = código ASCII - 48 ('0'=0..'9'=9, 'A'=17..'Z'=42)
const PESO1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
const PESO2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];

const normalizar = (s) => (s || '').toUpperCase().replace(/[^A-Z0-9]/g, '');

function digito(base, pesos) {
  let soma = 0;
  for (let i = 0; i < base.length; i++) soma += (base.charCodeAt(i) - 48) * pesos[i];
  const resto = soma % 11;
  return resto < 2 ? 0 : 11 - resto;
}

function calcularDV(base12) {            // base12 = 12 primeiras posições
  const d1 = digito(base12, PESO1);
  const d2 = digito(base12 + d1, PESO2);
  return `${d1}${d2}`;
}

function validarCNPJ(cnpj) {
  const c = normalizar(cnpj);
  if (!/^[A-Z0-9]{12}[0-9]{2}$/.test(c)) return false;
  if (/^0{12}/.test(c)) return false;     // base zerada
  return calcularDV(c.slice(0, 12)) === c.slice(12);
}

// validarCNPJ('12.ABC.345/01DE-35'); // true

Registrando a regra via mixin e requirejs-config

O ponto de extensão correto no Magento 2 é um mixin RequireJS sobre o módulo Magento_Ui/js/lib/validation/validator. Crie um módulo (ex.: app/code/Vendor/CnpjAlfanumerico) com o requirejs-config.js declarando o mixin no escopo frontend.

JavaScript
// app/code/Vendor/CnpjAlfanumerico/view/frontend/requirejs-config.js
var config = {
    config: {
        mixins: {
            'Magento_Ui/js/lib/validation/validator': {
                'Vendor_CnpjAlfanumerico/js/cnpj-rule': true
            }
        }
    }
};

O mixin recebe o objeto validator e chama addRule para registrar a regra cnpj-alfanumerico. Aqui colamos a lógica golden e devolvemos o validador original intacto.

JavaScript
// app/code/Vendor/CnpjAlfanumerico/view/frontend/web/js/cnpj-rule.js
define([], function () {
    'use strict';

    const PESO1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
    const PESO2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];

    const normalizar = (s) => (s || '').toUpperCase().replace(/[^A-Z0-9]/g, '');

    function digito(base, pesos) {
        let soma = 0;
        for (let i = 0; i < base.length; i++) soma += (base.charCodeAt(i) - 48) * pesos[i];
        const resto = soma % 11;
        return resto < 2 ? 0 : 11 - resto;
    }

    function calcularDV(base12) {
        const d1 = digito(base12, PESO1);
        const d2 = digito(base12 + d1, PESO2);
        return `${d1}${d2}`;
    }

    function validarCNPJ(cnpj) {
        const c = normalizar(cnpj);
        if (!/^[A-Z0-9]{12}[0-9]{2}$/.test(c)) return false;
        if (/^0{12}/.test(c)) return false;
        return calcularDV(c.slice(0, 12)) === c.slice(12);
    }

    return function (validator) {
        validator.addRule(
            'cnpj-alfanumerico',
            function (value) {
                if (!value) return true; // 'required' cuida do vazio
                return validarCNPJ(value);
            },
            'Informe um CNPJ válido (aceita letras e números).'
        );
        return validator;
    };
});

Por fim, aponte o campo do CNPJ para a nova regra. Se o campo vem por um módulo brasileiro no atributo taxvat/vat_id, adicione "cnpj-alfanumerico": true no array validation do componente UI (via customer_account_create.xml ou no layout do checkout). Em um formulário .phtml simples, basta a classe data-validate='{"cnpj-alfanumerico": true}' no input.

Validação server-side (PHP) com um plugin

Validação no navegador é UX, não segurança: um pedido pode chegar pela API REST, pelo painel admin ou com o JS desabilitado. Por isso, valide também no servidor. O ponto de extensão correto é um plugin declarado no di.xml sobre o método de validação do cliente (Magento\Customer\Model\Customer::validate) ou um observer no evento de salvamento. Comece pela função golden em PHP.

PHP
<?php
namespace Vendor\CnpjAlfanumerico\Model;

class CnpjValidator
{
    private const PESO1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
    private const PESO2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];

    private function normalizar(string $s): string
    {
        return preg_replace('/[^A-Z0-9]/', '', strtoupper($s));
    }

    private function digito(string $base, array $pesos): int
    {
        $soma = 0;
        for ($i = 0; $i < strlen($base); $i++) {
            $soma += (ord($base[$i]) - 48) * $pesos[$i];
        }
        $resto = $soma % 11;
        return $resto < 2 ? 0 : 11 - $resto;
    }

    private function calcularDv(string $base12): string
    {
        $d1 = $this->digito($base12, self::PESO1);
        $d2 = $this->digito($base12 . $d1, self::PESO2);
        return $d1 . $d2;
    }

    public function validar(string $cnpj): bool
    {
        $c = $this->normalizar($cnpj);
        if (!preg_match('/^[A-Z0-9]{12}[0-9]{2}$/', $c)) {
            return false;
        }
        if (preg_match('/^0{12}/', $c)) {
            return false;
        }
        return $this->calcularDv(substr($c, 0, 12)) === substr($c, 12);
    }
}

Agora plugue essa classe na validação do cliente. Declare o plugin no di.xml e implemente um after que injeta o erro quando o CNPJ for inválido.

PHP
<!-- app/code/Vendor/CnpjAlfanumerico/etc/di.xml -->
<config>
    <type name="Magento\Customer\Model\Customer">
        <plugin name="vendor_cnpj_alfanumerico_validate"
                type="Vendor\CnpjAlfanumerico\Plugin\ValidateCnpj" />
    </type>
</config>
PHP
<?php
namespace Vendor\CnpjAlfanumerico\Plugin;

use Magento\Customer\Model\Customer;
use Vendor\CnpjAlfanumerico\Model\CnpjValidator;

class ValidateCnpj
{
    public function __construct(private CnpjValidator $validator) {}

    /**
     * @param Customer $subject
     * @param array|true $result  resultado original do validate()
     */
    public function afterValidate(Customer $subject, $result)
    {
        $cnpj = (string) $subject->getTaxvat(); // ou getData('vat_id')
        if ($cnpj !== '' && !$this->validator->validar($cnpj)) {
            $errors = is_array($result) ? $result : [];
            $errors[] = __('Informe um CNPJ válido (aceita letras e números).');
            return $errors;
        }
        return $result;
    }
}

Como testar

Resumo rápido
  • Rode setup:upgrade, setup:di:compile e setup:static-content:deploy para publicar o mixin.
  • No checkout, digite um CNPJ alfanumérico válido e um com DV errado — só o segundo deve falhar.
  • Confirme o server-side via API REST ou criando o cliente pelo admin com JS desligado.
  • Gere massa de teste com o nosso gerador de CNPJ alfanumérico e confira no validador de CNPJ alfanumérico.
CNPJTipoEsperado
12.ABC.345/01DE-35Alfanumérico (filial)Válido
XP.TO1.234/0001-20Alfanumérico (matriz)Válido
9F.8E7.D6C/0001-36Alfanumérico (matriz)Válido
A1.B2C.3D4/E5F6-68Alfanumérico (filial)Válido
11.222.333/0001-81Numérico clássicoVálido
12.ABC.345/01DE-34DV incorretoInválido

Perguntas frequentes

Preciso trocar o módulo brasileiro que já uso no Magento?

Não necessariamente. O mixin e o plugin acima sobrepõem a validação sem mexer no módulo. Se o módulo (Gabrielqs MageBR, Amasty BR ou similar) já expõe o campo no atributo taxvat/vat_id, basta apontar o campo para a regra cnpj-alfanumerico e deixar o plugin server-side cuidar do resto. Verifique apenas se o módulo não força type="number" ou máscara com \d.

Por que registrar a regra por mixin em vez de editar o validador?

Editar arquivos do core do Magento é descartado no próximo update. O mixin via requirejs-config.js é o ponto de extensão oficial: ele estende Magento_Ui/js/lib/validation/validator sem tocar no código original, chamando validator.addRule() de forma segura e atualizável.

Os CNPJs antigos dos meus clientes vão parar de funcionar?

Não. A função golden aceita tanto o formato numérico clássico quanto o alfanumérico — ambos passam pelo mesmo módulo 11. Os 14 caracteres e a máscara não mudaram, então cadastros existentes continuam válidos sem migração de dados.

Uso outra plataforma de e-commerce além do Magento; tem tutorial?

Sim. A mesma fórmula vale em qualquer stack — veja como adaptar no CNPJ alfanumérico no WooCommerce e na VTEX e Nuvemshop. Como o Magento é PHP, o pulo do gato é sempre o mesmo: substituir a regra numérica antiga pela lógica de ASCII−48.

Fontes: Receita Federal (IN RFB 2.229/2024) e nota técnica do Serpro sobre o CNPJ alfanumérico.

Assistente PP
Assistente PP
Online agora
Powered by Primeira Solução