-
Notifications
You must be signed in to change notification settings - Fork 221
Open
Description
On August 2024, the Brazilian Federal Revenue Service (Receita Federal) officially announced the adoption of alphanumeric CNPJ numbers starting July 2026. This change was published on their official website and is regulated by Normative Instruction RFB No. 2229/2024.
The new rule allows CNPJ numbers to contain uppercase letters (A-Z) in addition to digits (0-9). The check digit (DV) calculation remains numeric, but each character (letter or digit) is converted to its ASCII code and subtracted by 48, as specified in the Receita Federal's documentation.
References
- Receita Federal - CNPJ Alfanumérico
- Normative Instruction RFB No. 2119/2022
- Normative Instruction RFB No. 2229/2024
Possible solution
- Now it is accepting a alphanumeric CNPJ;
- Only uppercase letters is allowed;
- Using regex to validate the format and to apply or remove it;
- Removed
InvalidLength
exception. This case is covered by regex; - Simplifying the function
validate
.
Note: Only functions that I changed is present. I tried to make as few changes as possible.
Target file: stdnum/br/cnpj.py
import re
from stdnum.exceptions import *
_cnpj_re = re.compile(r"^([\dA-Z]{2})\.?([\dA-Z]{3})\.?([\dA-Z]{3})/?([\dA-Z]{4})-?(\d{2})$")
def compact(number: str) -> str:
return format(number, mask=r"\1\2\3\4\5")
def calc_check_digits(number: str) -> str:
"""Calculate the check digits for the number."""
number = [ord(d) - 48 for d in number[:-2]]
d1 = (11 - sum(((3 - i) % 8 + 2) * n
for i, n in enumerate(number[:12]))) % 11 % 10
d2 = (11 - sum(((4 - i) % 8 + 2) * n
for i, n in enumerate(number[:12])) -
2 * d1) % 11 % 10
return "%d%d" % (d1, d2)
def validate(number: str) -> str:
"""Check if the number provided is a valid CNPJ (including alphanumeric format)."""
number = compact(number)
if calc_check_digits(number) != number[-2:]:
raise InvalidChecksum()
return number
def format(number: str, mask: str = r"\1.\2.\3/\4-\5") -> str:
"""Format the number to the presentation format: 00.000.000/0000-00"""
match = _cnpj_re.match(number)
if not match:
raise InvalidFormat()
return match.expand(mask)
Metadata
Metadata
Assignees
Labels
No labels