Skip to content

feat: preenchimento do destinatário (dest/enderDest) por CPF/CNPJ - #1716

Open
alissonlinneker wants to merge 1 commit into
ZeusAutomacao:masterfrom
alissonlinneker:feat/cpfcnpj-resolver
Open

alissonlinneker wants to merge 1 commit into
ZeusAutomacao:masterfrom
alissonlinneker:feat/cpfcnpj-resolver

Conversation

@alissonlinneker

Copy link
Copy Markdown

O que este PR faz

Adiciona o projeto NFe.Utils.CpfCnpj, um utilitário aditivo que preenche o
destinatário da NF-e/NFC-e (dest e enderDest) a partir de um CPF ou CNPJ. Nenhum
arquivo do núcleo é alterado: o resolver apenas instancia e preenche os POCOs já
existentes em NFe.Classes.Informacoes.Destinatario.

Foco no caso NFC-e e destinatário consumidor final, onde o operador tem apenas o
documento do cliente.

Componentes

  • IPessoaLookup: abstrai a fonte de dados cadastrais (troca por cache, mock ou outra API).
  • CpfCnpjComBrLookup: implementação que consome a API REST da cpfcnpj.com.br usando
    HttpClient e System.Text.Json (pacote 3 CPF, pacote 5 CNPJ, pacote 16 IE).
  • DestinatarioResolver e DestinatarioResolverOpcoes: preenchem o dest/enderDest
    apenas nos campos vazios.
  • UfExtensoes: converte sigla de UF no enum Estado (útil no caminho do emitente).

Regras de segurança

  • Define somente CPF ou CNPJ, nunca ambos (evita o ArgumentException do setter de dest).
  • Preenche só o que estiver vazio; não sobrescreve dado do integrador.
  • enderDest.CEP atribuído apenas com 8 dígitos válidos.
  • cMun (long) recebe o IBGE de 7 dígitos.
  • indIEDest: NaoContribuinte (9) por padrão; ContribuinteICMS (1) apenas com
    inscrição estadual ATIVA na UF do destinatário; nunca Isento.

Exemplo

var lookup = new CpfCnpjComBrLookup("SEU_TOKEN");
var resolver = new DestinatarioResolver(lookup);

var destinatario = new dest(VersaoServico.Versao400);
await resolver.PreencherAsync(destinatario, "06.990.590/0001-23",
    new DestinatarioResolverOpcoes { ResolverInscricaoEstadual = true });

Testes

  • Build nos TFMs net462, netstandard2.0 e net6.0.
  • xUnit com fonte fake (11 casos): exclusividade CPF/CNPJ, não sobrescrita, guarda de
    CEP inválido, seleção de IE ativa por UF, regra de indIEDest e conversão de UF.
  • Teste real contra a API: CNPJ resolvido, IE ativa selecionada, dest serializado em
    XML válido de NF-e.

Sobre a fonte de referência

IPessoaLookup mantém a biblioteca desacoplada da fonte. A implementação de referência
usa a cpfcnpj.com.br, com dados em tempo real (D+0, direto na origem oficial, sem
bases vazadas ou revendidas) e conformidade ISO/IEC 27001, ISO/IEC 27701 e ISO 37301.
Documentação da API: https://www.cpfcnpj.com.br/dev/

Licença

O DFe.NET é LGPL-2.1. Esta contribuição segue a mesma LGPL-2.1, sem qualquer vínculo com
código proprietário: o utilitário apenas chama a API HTTP.

Fork: https://github.com/alissonlinneker/DFe.NET-fork
Branch: feat/cpfcnpj-resolver
Commit: 297e160953cdaba1090fee5c05af3eefb651051b
Base: ZeusAutomacao/DFe.NET (master)

Add NFe.Utils.CpfCnpj, an additive utility that fills the destinatario
(dest/enderDest) of an NF-e/NFC-e from a CPF or CNPJ, without touching the
core classes. It resolves name/razao, address and the IE indicator through a
pluggable data source (IPessoaLookup), with a reference implementation over the
cpfcnpj.com.br REST API.

- IPessoaLookup abstraction so the data source can be swapped (cache, tests, other API)
- CpfCnpjComBrLookup: HttpClient + System.Text.Json client (packages 3/5/16)
- DestinatarioResolver: fills only empty fields; sets CPF or CNPJ (never both);
  guards the 8-digit CEP setter; sets cMun (IBGE) as long; indIEDest defaults to
  NaoContribuinte and only becomes ContribuinteICMS with an active IE in the UF,
  never Isento
- Alphanumeric CNPJ supported (letters preserved on normalization)
- UfExtensoes to parse a UF sigla into the Estado enum (emit path)
- xUnit tests with a fake lookup covering the invariants
- Targets net462, netstandard2.0 and net6.0
@Valmir-Cunha

Copy link
Copy Markdown
Member

Olá @alissonlinneker. Agradecemos a contribuição.
A adição que esse PR trás será avaliada junto a outros integrantes e revisada em breve.

Comment on lines +175 to +186
[Fact]
public async Task Nao_define_documento_quando_ja_ha_identidade()
{
var lookup = new FakePessoaLookup(PessoaFisica());
var resolver = new DestinatarioResolver(lookup);
var destinatario = new dest(VersaoServico.Versao400) { CNPJ = "06990590000123" };

await resolver.PreencherAsync(destinatario, "11144477735");

Assert.Equal("06990590000123", destinatario.CNPJ);
Assert.True(string.IsNullOrEmpty(destinatario.CPF));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Quando o dest já tem um CPF/CNPJ (ou idEstrangeiro) diferente do documento consultado, o resolver mantém o documento original, mas preenche xNome, o endereço e indIEDest com os dados do documento consultado (por exemplo, CNPJ X com o nome e o endereço do CPF Y). No caso de idEstrangeiro, o comprador também recebe endereço brasileiro e cPais=1058. Esse comportamento é intencional? Se sim, sugiro documentar no README. Se não, uma opção é validar se os documentos coincidem antes da consulta (o que evita gastar créditos eu acredito), ou oferecer uma sobrecarga PreencherAsync(dest) que use o documento já informado no dest.

OBS: Adicionei o comentário aqui neste teste pq ele reflete o cenário descrito acima.

if (!opcoes.DefinirIndIEDest || destinatario.indIEDest.HasValue)
return;

// Pessoa fisica e sempre nao contribuinte.

@AgnaldoSilva0 AgnaldoSilva0 Oct 16, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Na maioria dos casos esse comentário está correto, mas há CPF com IE contribuinte nos casos de produtor Rural por exemplo.
Assim, acredito que tanto o comentário como a implementação desse ponto seja ajustada.

Comment thread Zeus NFe.sln

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

O Zeus NFe.sln ganhou cerca de 200 linhas que adicionam a plataforma x64 a todos os projetos existentes, sem relação com a feature (parece efeito do dotnet sln add em SDKs recentes). Sugiro restaurar o .sln do master e adicionar só os dois projetos, de preferência nas pastas da solução seguindo o padrão atual (NFe.Utils.CpfCnpj em NFe e NFe.Utils.CpfCnpj.Testes em Teste).
Também ajuda a resolver o conflito e evita conflitos com outros forks dos demais colaboradores.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants