Primeira nota¶
Este guia monta uma NF-e de venda com um item, do zero até o arquivo de distribuição, em ambiente de homologação. Copie, cole, troque os dados do emitente pelos seus e rode.
Homologação não tem valor fiscal
Tudo aqui usa nfe.Homologacao. Notas emitidas nesse ambiente não valem
como documento fiscal e são descartadas pela SEFAZ periodicamente — é onde
se erra à vontade. Só troque para nfe.Producao depois que o cenário
tributário estiver conferido.
1. Carregar o certificado¶
cert, err := certificado.CarregarArquivo("certificado.pfx", os.Getenv("GONFE_SENHA"))
if err != nil {
return err
}
log.Println(cert.Descrever())
Descrever imprime razão social, CNPJ, autoridade emissora e validade — vale a
pena registrar isso no log de inicialização do seu sistema, porque certificado
vencido é a causa de falha mais chata de diagnosticar.
2. Identificação da nota¶
n := nfe.Nova(nfe.ModeloNFe)
ide := &n.InfNFe.Ide
ide.NatOp = "VENDA DE MERCADORIA ADQUIRIDA DE TERCEIROS"
ide.Serie = 1
ide.NNF = 57
ide.DhEmi = tipos.AgoraEm(uf.RS.Fuso())
ide.CMunFG = 4314902 // código do IBGE do município
ide.TpAmb = nfe.Homologacao
ide.IndFinal = "1" // operação com consumidor final
ide.IndPres = nfe.PresencaPresencial
nfe.Nova já preenche os campos estruturais com os padrões do leiaute: versão
4.00, emissão normal, DANFE em retrato, operação de saída interna.
O fuso horário importa
A SEFAZ confere se o deslocamento informado em dhEmi corresponde ao fuso
legal da UF do emitente. uf.RS.Fuso() devolve UTC−03:00; uf.AM.Fuso()
devolve UTC−04:00; uf.AC.Fuso(), UTC−05:00. Usar o fuso da máquina que
roda o servidor é um erro comum quando o servidor está em outra região.
3. Emitente¶
n.InfNFe.Emit = nfe.Emit{
CNPJ: "12345678000195",
XNome: "COMERCIO EXEMPLO LTDA",
XFant: "EXEMPLO",
IE: "0961234567",
CRT: nfe.RegimeNormal, // ou nfe.SimplesNacional
EnderEmit: nfe.Endereco{
XLgr: "AV IPIRANGA", Nro: "1000", XBairro: "PRAIA DE BELAS",
CMun: 4314902, XMun: "PORTO ALEGRE", UF: "RS", CEP: "90160091",
CPais: 1058, XPais: "BRASIL",
},
}
A UF do endereço do emitente determina o código que entra na chave de acesso —
não é preciso preencher ide.CUF à mão.
4. Destinatário¶
n.InfNFe.Dest = &nfe.Dest{
CPF: "52998224725",
XNome: nfe.TextoObrigatorioHomologacao,
IndIEDest: nfe.NaoContribuinte,
EnderDest: &nfe.Endereco{
XLgr: "RUA DAS FLORES", Nro: "42", XBairro: "CENTRO",
CMun: 4314902, XMun: "PORTO ALEGRE", UF: "RS", CEP: "90010000",
CPais: 1058, XPais: "BRASIL",
},
}
A razão social em homologação é fixa
Em homologação a SEFAZ exige que o destinatário se chame exatamente
NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL. A constante
nfe.TextoObrigatorioHomologacao guarda esse texto, e Validar aponta o
erro se ele estiver diferente.
5. Itens¶
valor := tipos.D("149.90")
n.InfNFe.Det = []nfe.Det{{
Prod: nfe.Prod{
CProd: "TEC-001", CEAN: "SEM GTIN", XProd: "TECLADO MECANICO ABNT2",
NCM: "84716053", CFOP: "5102", UCom: "UN",
QCom: tipos.D("1"), VUnCom: valor, VProd: valor,
CEANTrib: "SEM GTIN", UTrib: "UN", QTrib: tipos.D("1"), VUnTrib: valor,
IndTot: nfe.CompoeTotal,
},
Imposto: nfe.Imposto{
ICMS: &nfe.ICMS{ICMS00: &nfe.ICMS00{
Orig: nfe.OrigemNacional, CST: "00", ModBC: "3",
VBC: valor, PICMS: tipos.D("18.00"),
VICMS: valor.Percentual(tipos.D("18.00"), 2),
}},
PIS: &nfe.PIS{PISNT: &nfe.PISNT{CST: "07"}},
COFINS: &nfe.COFINS{COFINSNT: &nfe.COFINSNT{CST: "07"}},
},
}}
Repare em três coisas:
tipos.Dem vez de literais numéricos. Nunca usefloat64para valor fiscal; veja Valores decimais.Percentualcalcula o tributo com arredondamento comercial na precisão do campo.valor.Percentual(aliquota, 2)évalor × alíquota ÷ 100arredondado para dois dígitos."SEM GTIN"quando não há código de barras. O campo é obrigatório; deixar vazio é rejeição certa.
O grupo ICMS é uma união: preencha exatamente um dos campos, escolhido pelo CST
(regime normal) ou pelo CSOSN (Simples Nacional). Um item de serviço usa
Imposto.ISSQN no lugar do ICMS.
6. Transporte e pagamento¶
n.InfNFe.Transp = nfe.Transp{ModFrete: nfe.SemFrete}
n.InfNFe.Pag = &nfe.Pag{DetPag: []nfe.DetPag{{
TPag: nfe.PagamentoCartaoCredito,
VPag: valor,
}}}
O grupo de pagamento é obrigatório no leiaute 4.00, inclusive na NF-e. A soma
dos pagamentos precisa bater com o valor total da nota mais o troco — Validar
confere isso.
7. Preparar, validar e assinar¶
if err := n.Preparar(); err != nil {
return err
}
if err := n.Validar(); err != nil {
return err // devolve nfe.Erros, com um item por inconsistência
}
assinada, err := n.AssinarCom(cert)
if err != nil {
return err
}
log.Println("chave:", n.Chave())
Preparar normaliza os textos, ajusta a escala de todos os decimais, calcula o
grupo de totais e monta a chave de acesso. É idempotente: chamar duas vezes dá
o mesmo resultado.
8. Enviar e recolher o protocolo¶
cliente, err := sefaz.NovoCliente(sefaz.Config{
UF: uf.RS, Ambiente: nfe.Homologacao,
Modelo: nfe.ModeloNFe, Certificado: cert,
})
if err != nil {
return err
}
ctx, cancelar := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancelar()
lote, err := nfe.MontarLote(nfe.ProximoIdLote(time.Now().Unix()), false, assinada)
if err != nil {
return err
}
envio, err := cliente.Autorizar(ctx, lote)
if err != nil {
return err
}
resultado, err := cliente.EsperarProcessamento(ctx, envio.Recibo(), 3*time.Second, 20)
if err != nil {
return err
}
prot := resultado.ProtocoloDa(n.Chave())
if !prot.Autorizada() {
return fmt.Errorf("nota não autorizada: %s", prot.Resumo())
}
9. Guardar o arquivo de distribuição¶
proc, err := nfe.MontarNFeProc(assinada, prot)
if err != nil {
return err
}
os.WriteFile(n.Chave()+"-procNFe.xml", nfe.XMLDeclarado(proc), 0o644)
O nfeProc é o documento que precisa ser guardado por cinco anos e entregue ao
destinatário. Ele junta a nota assinada com o protocolo de autorização,
preservando byte a byte os dados que foram assinados.
Programa completo¶
O exemplo executável, com tratamento de erro e leitura de variáveis de
ambiente, está em
exemplos/emitir-nfe.