Files
GTI_GERENCIADOR_FISCAL/app/cnpj_lookup.py
T
Gustavo 3158a416a9 feat: preenchimento automatico de dados do cliente a partir do CNPJ
Ao sair do campo CNPJ no formulario de cliente, busca automaticamente
na BrasilAPI (publica, gratuita, sem chave - dados abertos da Receita)
e preenche Razao/Fantasia/Endereco/Cidade/Bairro/UF/CEP/Telefone/
E-mail, so nos campos que estiverem vazios (nunca sobrescreve o que
ja foi digitado). So funciona para CNPJ - CPF e dado pessoal, sem
consulta publica, e a rota recusa (404) se detectar CPF.

- app/cnpj_lookup.py: cliente HTTP pra BrasilAPI, degrada em silencio
  (retorna None) se nao encontrar/rede cair/formato nao reconhecido
  (ex.: CNPJ alfanumerico novo, que a BrasilAPI pode nao cobrir ainda).
- Nova rota GET /clientes/consulta-cnpj/{documento}, chamada via
  fetch() no formulario (JS vanilla, sem framework).
- Testado ponta a ponta contra a API real.

106/106 testes passando (10 novos).
2026-08-13 15:05:26 -03:00

58 lines
2.2 KiB
Python

"""
Consulta de CNPJ na BrasilAPI (https://brasilapi.com.br/api/cnpj/v1) para
preencher automaticamente o formulário de cliente. Fonte pública/gratuita,
sem autenticação, mantida pela comunidade a partir de dados abertos da
Receita Federal — não é a API oficial da Receita (que não tem consulta
pública direta por CNPJ).
Só faz sentido para CNPJ (empresa) — CPF é dado pessoal e não tem consulta
pública, então o chamador nunca deve passar um CPF aqui (ver
app/routers/clientes.py, que checa o tipo via normalizar_documento antes).
Degrada de forma segura: qualquer falha (CNPJ não encontrado, rede fora do
ar, formato que a BrasilAPI ainda não reconhece — o novo CNPJ alfanumérico,
vigente desde 31/07/2026, pode não estar coberto por todo provedor ainda)
retorna None. O formulário simplesmente não preenche nada sozinho nesse caso.
"""
import httpx
_BASE_URL = "https://brasilapi.com.br/api/cnpj/v1"
def consultar_cnpj(cnpj_normalizado: str) -> dict | None:
"""
cnpj_normalizado: 14 caracteres (12 alfanuméricos + 2 dígitos), já sem
máscara — ver app/normalize.py. Retorna um dict só com os campos que
existem em CLIENTE, prontos para preencher o formulário, ou None se não
encontrou/a consulta falhou.
"""
if len(cnpj_normalizado) != 14:
return None
try:
resposta = httpx.get(f"{_BASE_URL}/{cnpj_normalizado}", timeout=8.0)
if resposta.status_code != 200:
return None
dados = resposta.json()
except (httpx.HTTPError, ValueError):
return None
if not isinstance(dados, dict):
return None
logradouro = dados.get("logradouro") or ""
numero = dados.get("numero") or ""
endereco = f"{logradouro}, {numero}" if numero else logradouro
return {
"RAZAO": dados.get("razao_social") or "",
"FANTASIA": dados.get("nome_fantasia") or dados.get("razao_social") or "",
"ENDERECO": endereco[:45], # CLIENTE.ENDERECO é varchar(45)
"CIDADE": dados.get("municipio") or "",
"BAIRRO": dados.get("bairro") or "",
"UF": dados.get("uf") or "",
"CEP": (dados.get("cep") or "")[:10],
"TELEFONE": dados.get("ddd_telefone_1") or "",
"EMAIL": dados.get("email") or "",
}