Skip to content

feat(formatter): aceitar CNPJ alfanumerico (Reforma Tributaria 2026-07-01)#36

Open
rhfranzoni wants to merge 2 commits into
mainfrom
feat/cnpj-alphanumeric-formatter
Open

feat(formatter): aceitar CNPJ alfanumerico (Reforma Tributaria 2026-07-01)#36
rhfranzoni wants to merge 2 commits into
mainfrom
feat/cnpj-alphanumeric-formatter

Conversation

@rhfranzoni
Copy link
Copy Markdown

Resumo

A SEFAZ vai aceitar CNPJ alfanumerico a partir de 2026-07-01 (LC 214/2025, IN RFB 2.229/2024). 12 primeiros caracteres podem conter letras maiusculas; 2 ultimos seguem como digitos verificadores numericos.

Hoje o Formatador.FormatarCnpj/FormatarCpfCnpj usa regex \d que rejeita letras — efeito pratico: a partir de 2026-07-01 o DANFE/cupom passa a renderizar CNPJ alfanumerico sem mascara visual, prejudicando legibilidade fiscal.

Mudancas

DanfeSharp/Formatador.cs

  • Regex CNPJ: 4 primeiros grupos passam de \d para [0-9A-Z]. Ultimo grupo (DV) permanece \d.
  • FormatarCpfCnpj: reescrita para decidir por comprimento da string limpa antes da regex (elimina ambiguidade entre CPF e CNPJ alfanumerico).
  • CPF regex: inalterada (CPF segue numerico por norma RFB).

DanfeSharp.Test/FormatadorTests.cs (novo)

30+ casos via DataTestMethod / DataRow:

  • Regressao: CNPJs/CPFs numericos legados.
  • Novos casos: CNPJ alfanumerico em multiplas posicoes (12ABC345000188, 98XYZ123000158).
  • Rejeicao: lowercase, DV alfabetico, comprimento invalido.
  • Edge cases: null, vazio, espacos, ja-formatado.

Validacao

  • DLL principal (DanfeSharp.csproj) compila sem erros.
  • Validacao via dotnet-script chamando Formatador.FormatarCnpj / FormatarCpfCnpj com 13 vetores: 13/13 OK.

Ressalva

O test project DanfeSharp.Test ja apresentava erros preexistentes de compilacao em FabricaFake.cs e DanfeTest.cs (DanfeCCC nao encontrado, conversao double->decimal) na branch main antes deste PR. Esses erros nao foram introduzidos aqui e nao tocam no codigo modificado. Como follow-up separado: corrigir o test project para que dotnet test rode completo.

Issues vinculadas

  • Closes #35 apos serem feitos os outros PRs derivados (esta e a primeira etapa).
  • Relacionada #33 (barcode CODE-128A/C com CNPJ alfanumerico) — esta PR resolve o requisito de tipagem; barcode em si segue como track paralelo.

Test plan

  • DLL compila
  • dotnet-script valida 13/13 vetores (CNPJ numerico, alfanumerico, CPF, edge cases)
  • CI do fork (se configurado) executa o test project corrigido
  • Revisor humano valida a regex e o switch por length

Breaking changes

Nenhuma:

  • CNPJs numericos legados formatam exatamente como antes.
  • Comprimento invalido devolve input trimado (sem exception) — mesmo contrato historico.
  • Null / vazio retornam string vazia — mesmo contrato historico.

Pessoas consumindo FormatarCnpj precisam estar preparadas para receber strings com letras no retorno a partir de 2026-07-01 — mas o tipo de retorno (string) e o formato visual (XX.XXX.XXX/XXXX-XX) sao os mesmos.

Generated with Claude Code (https://claude.com/claude-code)

…7-01)

A partir de 2026-07-01 a SEFAZ aceitara CNPJ no formato alfanumerico
(LC 214/2025 + IN RFB 2.229/2024). 12 primeiros caracteres podem
conter letras maiusculas [A-Z], dois ultimos seguem como digitos
verificadores numericos.

## Mudancas no Formatador

- Regex CNPJ: `\d{2}` -> `[0-9A-Z]{2}` nos 4 primeiros grupos (12 chars);
  ultimo grupo (2 digitos verificadores) inalterado.
- CPF regex inalterado (CPF segue sendo \d{11} por norma RFB).
- `FormatarCpfCnpj` reescrita para decidir por **comprimento da string limpa
  (sem mascara)** antes da regex. Elimina ambiguidade quando um CNPJ
  alfanumerico hipoteticamente pudesse bater na regex CPF (improvavel mas
  deterministico de mitigar).

## Comportamento preservado

- CNPJs/CPFs numericos legados continuam formatando exatamente como antes.
- Comprimento invalido devolve input trimado (sem exception) — mesmo
  contrato historico.
- Null / vazio devolvem string vazia — mesmo contrato historico.

## Cobertura

Adicionado `DanfeSharp.Test/FormatadorTests.cs` com 30+ casos usando
DataTestMethod/DataRow (MSTest 1.1):

- CNPJ numerico legado (regressao)
- CNPJ alfanumerico em varias posicoes de letras
- CNPJ com mascara visual (idempotencia)
- CNPJ comprimento invalido / lowercase / DV alfabetico (todos rejeitados)
- CPF numerico
- CPF com letras (rejeitado — nunca aceita alfanumerico)
- FormatarCpfCnpj dispatching por comprimento (11=CPF, 14=CNPJ, outros=cru)
- Edge cases: null, vazio, espacos

> Nota: o test project (DanfeSharp.Test) ja apresentava erros
> preexistentes de compilacao em FabricaFake.cs e DanfeTest.cs (na main
> antes deste PR). Validacao da nova logica feita via dotnet-script
> contra a DLL compilada — 13/13 checks OK. Restauracao dos testes
> existentes fica como follow-up separado.

Issue: #35 (spike). Cobre tambem o tipo basico exigido
pela issue #33 (barcode CNPJ alfanumerico).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 28, 2026 02:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates document formatting so Formatador can apply the standard CNPJ mask to the upcoming alphanumeric CNPJ format while preserving CPF behavior and numeric CNPJ regressions.

Changes:

  • Updates the CNPJ regex to allow uppercase letters in the first 12 characters while keeping numeric check digits.
  • Rewrites FormatarCpfCnpj to dispatch by cleaned document length before applying CPF/CNPJ formatting.
  • Adds MSTest coverage for CPF, numeric CNPJ, alphanumeric CNPJ, invalid inputs, null/empty, and masked inputs.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
DanfeSharp/Formatador.cs Adds alphanumeric CNPJ support and changes CPF/CNPJ dispatch logic.
DanfeSharp.Test/FormatadorTests.cs Adds formatter regression and alphanumeric CNPJ test cases.
DanfeSharp.Test/DanfeSharp.Test.csproj Includes the new formatter test file in the legacy test project.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread DanfeSharp/Formatador.cs Outdated
…o invalido

Endereca o review do Copilot no PR #36 (comentario inline em Formatador.cs L150).

## Bug

Quando o input tinha comprimento "limpo" 11 ou 14 mas conteudo invalido
(ex.: CNPJ alfanumerico com letras minusculas: "12.abc.345/0001-88"),
o dispatch por comprimento mandava para FormatarCnpj("12abc345000188"),
a regex rejeitava (so aceita [0-9A-Z] maiusculo), e o retorno era o
clean cru — **perdendo a pontuacao visivel do input original**.

Comportamento histórico (antes do PR #36): regex miss devolvia o input
trimado inalterado, mantendo pontuacao.

## Fix

Valida `clean` contra a regex correspondente ANTES do dispatch:

```csharp
if (clean.Length == 11 && Regex.IsMatch(clean, CPF))
    return FormatarCpf(clean);
if (clean.Length == 14 && Regex.IsMatch(clean, CNPJ))
    return FormatarCnpj(clean);
return trimmed;  // Conteudo nao bate na regex — devolve com pontuacao
```

Comportamento agora alinhado com o contrato historico: input invalido
(comprimento, formato, lowercase em CNPJ alfanumerico, DV alfabetico)
devolve `trimmed` — preservando o input visivel para que o caller
identifique o problema sem corrupcao silenciosa.

## Testes adicionados

`DanfeSharp.Test/FormatadorTests.cs`:
- `FormatarCpfCnpj_InvalidoComMascara_PreservaPontuacaoDoInput` (4 cenarios):
  - CNPJ alfanumerico minusculo com mascara: `"12.abc.345/0001-88"` -> identico
  - CNPJ com DV alfabetico + mascara
  - CPF com letra + mascara
  - CNPJ todo letras + mascara (DV alfabetico rejeita)
- `FormatarCpfCnpj_InvalidoSemMascara_DevolveInputInalterado` (2 cenarios):
  - CNPJ lowercase sem mascara
  - CPF com letra sem mascara

Validacao via dotnet-script contra a DLL recem-buildada: 13/13 OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@john182 john182 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Review — PR #36 feat(formatter): CNPJ alfanumérico

Mudança cirúrgica e correta. Validei o Formatador.cs completo no head do PR (incl. InternalRegexReplace, FormatarCnpj/Cpf) — a lógica de produção está sólida e retrocompatível de fato. Comentários inline nos pontos específicos.

✅ Pontos fortes

  • Regex alinhada à norma: 12 primeiros [0-9A-Z] + DV \d{2} numérico (LC 214/2025).
  • Retrocompatível: CNPJ/CPF numéricos legados formatam idênticos; input inválido volta inalterado — mesmo contrato do InternalRegexReplace, que em regex-miss retorna o input.
  • O refactor (dispatch por comprimento → depois regex) preserva o contrato histórico "regex miss ⇒ input intocado" e ainda ganhou teste de regressão dedicado (...PreservaPontuacaoDoInput).
  • Cobertura de edge cases excelente (36 casos): null, vazio, espaços, lowercase, DV alfabético, com/sem máscara, idempotência.
  • Disclosure honesto do test project quebrado + análise de breaking changes.
  • Compile Include adicionado corretamente (csproj old-style, não SDK).

⚠️ Importante

Os 36 testes não executam — o assembly DanfeSharp.Test não compila (DanfeCCC inexistente em DanfeTest.cs:63, confirmado). Detalhe inline na csproj. É o único ponto que eu trataria antes do merge: teste que não roda não protege contra regressão.

💡 Menores

  • Nomes dos testes seguem Metodo_Cenario_Esperado (MSTest) em vez de Given/When/Then — ok, segue a convenção do repo.
  • Redundância na checagem de comprimento (inline, não bloqueia).

Veredito: lógica de produção aprovada. Recomendo destravar a execução do test project para que a rede de proteção realmente exista.

<Compile Include="DanfeXmlTests.cs" />
<Compile Include="Extentions.cs" />
<Compile Include="FabricaFake.cs" />
<Compile Include="FormatadorTests.cs" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Importante — estes testes não rodam via dotnet test. O assembly DanfeSharp.Test não compila: DanfeTest.cs:63 referencia DanfeCCC, classe que não existe no repo (confirmei). Enquanto o test project não buildar, os 36 casos deste arquivo não executam em CI nem localmente — só foram validados por dotnet-script, que exercita o Formatador mas não o arquivo de teste em si.

💡 Recomendo corrigir o test project neste PR (ou em PR pré-requisito mergeado antes deste). Caso contrário, são testes mortos até o follow-up — e o risco é que nunca rodem e a regex sofra regressão silenciosa.

Comment thread DanfeSharp/Formatador.cs
// CNPJ aceita letras maiúsculas nos 12 primeiros caracteres a partir de 2026-07-01
// (Reforma Tributária, LC 214/2025 e IN RFB 2.229/2024). Os 2 últimos seguem como
// dígitos verificadores numéricos. CPF permanece estritamente numérico.
public const String CNPJ = @"^([0-9A-Z]{2})\.?([0-9A-Z]{3})\.?([0-9A-Z]{3})\/?([0-9A-Z]{4})\-?(\d{2})$";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Regex correta conforme a norma: 12 primeiros [0-9A-Z], DV final \d{2} numérico.

💡 Decisão de design a confirmar: lowercase é rejeitado (volta sem máscara) em vez de normalizado para maiúsculo. É defensável — a forma canônica SEFAZ é maiúscula — e os testes assertam isso explicitamente. Só vale garantir que nenhum caminho upstream entregue o CNPJ em minúsculas ao formatador; se entregar, o DANFE renderiza sem máscara silenciosamente. Se houver essa dúvida, um .ToUpperInvariant() no clean resolveria de forma conservadora.

Comment thread DanfeSharp/Formatador.cs
// FormatarCnpj retornaria a string crua sem máscara, e a pontuação visível
// do input original seria perdida. Devolver `trimmed` para input inválido
// alinha com o contrato histórico: regex miss => input inalterado.
if (clean.Length == 11 && Regex.IsMatch(clean, CPF))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit (não bloqueia): clean.Length == 11 é redundante com a regex CPF, que é ancorada (^...$) e já exige exatamente 11 caracteres sobre a string limpa (idem == 14 para CNPJ). Mantê-lo como fast-path/intenção explícita é aceitável — só registrando que não é necessário para corretude.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants