Parsing de NF-e simplificado
Biblioteca Rust de alto desempenho para parsing e serialização de Nota Fiscal Eletrônica brasileira. Suporte ao Layout 4.00 da SEFAZ.
nfe = "0.1.0"
Funcionalidades
Tudo que você precisa para trabalhar com NF-e em Rust
Alto Desempenho
Parsing e serialização extremamente rápidos graças ao quick-xml e otimizações do Rust.
Type-Safe
Tipagem forte com enums para todos os campos codificados, prevenindo erros em tempo de compilação.
Layout 4.00
Suporte completo ao layout 4.00 da NF-e conforme especificação da SEFAZ.
Serialização
Converta facilmente entre estruturas Rust e XML válido para transmissão à SEFAZ.
Modelos Completos
Suporte a NF-e (modelo 55) e NFC-e (modelo 65) com todas as estruturas necessárias.
Bem Testado
Cobertura de testes abrangente para garantir a conformidade com o padrão da SEFAZ.
Fácil de Usar
Parse de XML de NF-e em poucas linhas de código. A biblioteca cuida de toda a complexidade do XML para você.
Acesse todos os campos da nota fiscal através de structs Rust bem tipadas e documentadas.
- Parse de arquivos XML
- Parse de strings XML
- Serialização para XML
- Validação automática de tipos
- Tratamento de erros robusto
use nfe::Nfe; fn main() -> Result<(), nfe::Error> { // Parse de string XML (sem namespace) let xml = std::fs::read_to_string("nota.xml")?; let xml = xml.replace( "xmlns=\"http://www.portalfiscal.inf.br/nfe\"", "" ); // Extrair tag <NFe> e fazer parse let nfe: Nfe = xml.parse()?; // Acessar dados da nota println!("Chave: {}", nfe.chave_acesso); println!("Emitente: {:?}", nfe.emit.razao_social); println!("Total: R$ {:.2}", nfe.totais.valor_total); // Iterar sobre os itens for item in &nfe.itens { println!("{}. {} - R$ {:.2}", item.numero, item.produto.descricao, item.produto.valor_bruto ); } Ok(()) }
Guia de Uso
Aprenda a utilizar a biblioteca passo a passo
use nfe::Nfe; // O XML da SEFAZ contém namespace que deve ser removido let xml_original = std::fs::read_to_string("nfe.xml")?; let xml = xml_original.replace( "xmlns=\"http://www.portalfiscal.inf.br/nfe\"", "" ); // Se o XML for nfeProc (com protocolo), extraia apenas a tag <NFe> let nfe_start = xml.find("<NFe").unwrap(); let nfe_end = xml.find("</NFe>").unwrap() + 6; let nfe_xml = &xml[nfe_start..nfe_end]; // Parse usando o trait FromStr let nfe: Nfe = nfe_xml.parse()?;
// Dados do emitente (quem emitiu a nota) if let Some(cnpj) = &nfe.emit.cnpj { println!("CNPJ: {}", cnpj); } if let Some(razao) = &nfe.emit.razao_social { println!("Razão Social: {}", razao); } // Endereço do emitente println!("Endereço: {}, {}", nfe.emit.endereco.logradouro, nfe.emit.endereco.numero ); println!("Cidade: {} - {}", nfe.emit.endereco.nome_municipio, nfe.emit.endereco.sigla_uf );
// Cada item contém produto, impostos e número sequencial for item in &nfe.itens { let prod = &item.produto; println!("Item {}: {}", item.numero, prod.descricao); println!(" Código: {}", prod.codigo); println!(" NCM: {}", prod.ncm); println!(" Qtd: {} {} x R$ {:.2} = R$ {:.2}", prod.quantidade, prod.unidade, prod.valor_unitario, prod.valor_bruto ); // CFOP está na tributação do produto println!(" CFOP: {}", prod.tributacao.cfop); // Verificar desconto if let Some(desc) = prod.valor_desconto { println!(" Desconto: R$ {:.2}", desc); } }
// Totais da nota fiscal println!("Valor Produtos: R$ {:.2}", nfe.totais.valor_produtos); println!("Valor Frete: R$ {:.2}", nfe.totais.valor_frete); println!("Valor Desconto: R$ {:.2}", nfe.totais.valor_desconto); println!("Valor Total: R$ {:.2}", nfe.totais.valor_total); println!("Tributos Aprox.: R$ {:.2}", nfe.totais.valor_aproximado_tributos); // Totais de ICMS println!("Base ICMS: R$ {:.2}", nfe.totais.base_calculo_icms); println!("Valor ICMS: R$ {:.2}", nfe.totais.valor_icms);
use nfe::{TipoAmbiente, ModeloDocumentoFiscal, TipoOperacao}; // Dados de identificação (ide) println!("Chave de Acesso: {}", nfe.chave_acesso); println!("Número: {}", nfe.ide.numero); println!("Série: {}", nfe.ide.serie); println!("Natureza: {}", nfe.ide.operacao.natureza); // Verificar ambiente (produção ou homologação) match nfe.ide.ambiente { TipoAmbiente::Producao => println!("Ambiente: Produção"), TipoAmbiente::Homologacao => println!("Ambiente: Homologação"), } // Verificar tipo de operação match nfe.ide.operacao.tipo { TipoOperacao::Entrada => println!("Operação: Entrada"), TipoOperacao::Saida => println!("Operação: Saída"), }
use nfe::{Nfe, Error}; fn processar_nfe(xml: &str) -> Result<Nfe, Error> { let nfe: Nfe = xml.parse()?; Ok(nfe) } fn main() { match processar_nfe(xml_content) { Ok(nfe) => { println!("NF-e processada: {}", nfe.chave_acesso); } Err(Error::Xml(e)) => { eprintln!("Erro de XML: {}", e); } Err(Error::Io(e)) => { eprintln!("Erro de IO: {}", e); } Err(e) => { eprintln!("Erro: {}", e); } } }
Estruturas Disponíveis
Todas as estruturas da NF-e mapeadas para Rust