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.
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.
// 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'); // trueRegistrando 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.
// 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.
// 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
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.
<!-- 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
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
- Rode
setup:upgrade,setup:di:compileesetup:static-content:deploypara 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.
| CNPJ | Tipo | Esperado |
|---|---|---|
12.ABC.345/01DE-35 | Alfanumérico (filial) | Válido |
XP.TO1.234/0001-20 | Alfanumérico (matriz) | Válido |
9F.8E7.D6C/0001-36 | Alfanumérico (matriz) | Válido |
A1.B2C.3D4/E5F6-68 | Alfanumérico (filial) | Válido |
11.222.333/0001-81 | Numérico clássico | Válido |
12.ABC.345/01DE-34 | DV incorreto | Invá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.
Ofertas em destaque
Ver todas →
Amazon
-27%
Hellmann's Maionese Light 500g
Mercado Livre
Kit 10 Pares Meia Invisível Unissex Soquete Algodão Selene 10 Branco Original Soquete Cano Curto G ( 39 A 44 )
Shopee
-60%
Brow Rise Gel Para Sobrancelhas By Ruby Rose Linha Rosa HB-E2503 Hot Sale
Shopee
-56%
Calça Pantalona Lanzinha Feminina Cintura Alta Com Elastico De e Bolso Outono / Inverno Promoção
Amazon
-93%
Tramontina Ducha Elétrica 3 Temperaturas 5500 W 127 V Chuveiro Branco
Amazon
Leite em Pó Ninho Integral Instantâneo Sachê 975g
Mercado Livre
Perfume Lattafa Bade'e Al Oud For Glory Edp Spray 100 Ml
Amazon
-14%
Lenços Umedecidos Huggies Rosto e Corpo Limpeza 4 x 48 Un
Shopee
-33%