Skip to content

feat: support alphanumeric CNPJ (July 2026 format) - #2

Merged
LeoColman merged 1 commit into
masterfrom
feat/alphanumeric-cnpj
Jul 22, 2026
Merged

feat: support alphanumeric CNPJ (July 2026 format)#2
LeoColman merged 1 commit into
masterfrom
feat/alphanumeric-cnpj

Conversation

@LeoColman

Copy link
Copy Markdown
Owner

What

Adds support for the alphanumeric CNPJ format, in effect since July 2026.

The first twelve characters may now be digits (0-9) or uppercase letters (A-Z); the last two remain numeric verification digits. Total length stays 14.

Algorithm

Each character is worth its ASCII code minus 48, so 0-9 map to 0-9 and A-Z continue the sequence from 17 (A) to 42 (Z). The module-11 weights are unchanged, which makes the change fully backwards compatible — every legacy numeric CNPJ still validates.

Verified against the official SERPRO / Receita Federal documentation, including its worked example 12.ABC.345/01DE → check digits 35.

Changes

  • isCnpj() accepts A-Z in the first 12 positions; last 2 must be digits.
  • Replaced Char.isDigit() with explicit '0'..'9' / 'A'..'Z' ranges — isDigit() accepts non-ASCII digits (e.g. Arabic-Indic ٦) that would corrupt the ASCII-48 math.
  • Long.isCnpj() unchanged (numeric-only by nature; an alphanumeric CNPJ is not representable as a number).
  • Lowercase letters rejected, per the spec (uppercase only).
  • README documents the new format.

Tests

  • Official Receita Federal example, raw and formatted.
  • 8 valid alphanumeric vectors + the same 8 with corrupted check digits.
  • New ValidNumericCnpjGenerator property test locking legacy numeric compatibility.
  • Rejection cases: lowercase, letters in DV positions, non-ASCII digits, junk chars.

All 16 tests pass; detekt clean.

Since July 2026 the CNPJ is alphanumeric: the first twelve characters
may be digits or uppercase letters (A-Z), while the last two remain
numeric verification digits. Each character is worth its ASCII code
minus 48 (0-9 = 0-9, A = 17 ... Z = 42); the module-11 weights are
unchanged, so every legacy numeric CNPJ stays valid.

Also replaces the isDigit() char check with explicit '0'..'9' / 'A'..'Z'
ranges, since Char.isDigit() accepts non-ASCII digits that would feed
garbage into the ASCII-48 calculation.

Reference: https://www.serpro.gov.br/menu/noticias/videos/calculodvcnpjalfanaumerico.pdf
@LeoColman
LeoColman merged commit 5e47522 into master Jul 22, 2026
2 checks passed
@LeoColman
LeoColman deleted the feat/alphanumeric-cnpj branch July 22, 2026 22:47
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.

1 participant