Class: SEFAZ::Webservice::NFE::Client

Inherits:
Base
  • Object
show all
Defined in:
lib/sefaz/webservice/nfe/client.rb

Overview

Principal classe de integração com o módulo NF-e/NFC-e

Constant Summary collapse

SERVICES =
%i[ setaAmbiente setaRespTecnico setaPFXTss setaPFXAss statusDoServico consultarNF consultarCadastro consultarRecibo
assinarNF validarNF auditarNF inutilizarNF exportarInutilizarNF enviarInutilizarNF calculaChaveInutilizacao
enviarEvento enviarLoteDeEvento cancelarNF exportarCancelarNF enviarCCe exportarCCe enviarNF enviarLoteNF calculaChaveNF]

Instance Method Summary collapse

Constructor Details

#initializeClient

Métodos de Manipulação: (MAIORIA EXIGE ASSINATURA) – Os métodos ‘enviarNF’ e ‘enviarLoteNF’ não precisa ‘exportar’, pois os dados são montados externo à gema (XML ou Hash ou Dataset)

  • assinarNF

  • enviarNF

  • enviarLoteNF

  • calculaChaveNF

  • inutilizarNF

    • exportarInutilizarNF

    • enviarInutilizarNF

    • calculaChaveInutilizacao

  • cancelarNF (EVENTO)

    • exportarCancelarNF (EVENTO)

  • enviarCCe (EVENTO)

    • exportarCCe (EVENTO)

  • enviarManifestacao (PENDENTE) (EVENTO)

    • exportarManifestacao (PENDENTE) (EVENTO)

  • enviarEvento

  • enviarLoteDeEvento

  • gerarLeiauteEvento (PRIVADO)



50
51
# File 'lib/sefaz/webservice/nfe/client.rb', line 50

def initialize
end

Instance Method Details

#assinarNF(documento) ⇒ Object

Assinar NF - PFX de assinatura - Certificado A1 @documento(Hash ou String) = XML ou HASH que será assinado



128
129
130
131
132
133
134
# File 'lib/sefaz/webservice/nfe/client.rb', line 128

def assinarNF(documento)
  xml = (documento.is_a?(Hash) ? documento.to_xml! : documento)
  doc = SEFAZ::Utils::Signer.new(xml)
  doc.sign!(@pkcs12Ass.certificate, @pkcs12Ass.key)
  xml = doc.to_xml
  return [xml, xml.to_hash!]
end

#auditarNF(documento, openTimeout = 60, readTimeout = 60) ⇒ Object

Auditar NF no validador TecnoSpeed (validador.nfe.tecnospeed.com.br/) @documento(Hash ou String) = XML ou HASH que será auditado @openTimeout(Integer) = Tempo de espera em segundos para abrir conexão (opcional: padrão 60) @readTimeout(Integer) = Tempo de espera em segundos para ler resposta (opcional: padrão 60)



210
211
212
213
214
215
216
217
218
# File 'lib/sefaz/webservice/nfe/client.rb', line 210

def auditarNF(documento, openTimeout = 60, readTimeout = 60)
  xml = (documento.is_a?(Hash) ? documento.to_xml! : documento)
  auditor = SEFAZ::Webservice::NFE::Auditor.new(xml)
  stat, msg = auditor.exec(openTimeout, readTimeout)
  case stat
  when :ok; return [true, msg]
  else      return [false, {}]
  end
end

#calculaChaveInutilizacao(ano, cnpj, modelo, serie, nroNFIni, nroNFFin) ⇒ Object

Calcular Chave de Inutilização



242
243
244
245
246
247
# File 'lib/sefaz/webservice/nfe/client.rb', line 242

def calculaChaveInutilizacao(ano, cnpj, modelo, serie, nroNFIni, nroNFFin)
  serie = serie.to_s.rjust(3, "0")
  nroNFIni = nroNFIni.to_s.rjust(9, "0")
  nroNFFin = nroNFFin.to_s.rjust(9, "0")
  return "ID#{@uf}#{ano}#{cnpj}#{modelo}#{serie}#{nroNFIni}#{nroNFFin}"
end

#calculaChaveNF(uf, aamm, cnpj, modelo, serie, nNF, tpEmis, cNF) ⇒ Object

Calcular Chave NF



178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/sefaz/webservice/nfe/client.rb', line 178

def calculaChaveNF(uf, aamm, cnpj, modelo, serie, nNF, tpEmis, cNF)
  uf = uf.to_s.rjust(2, "0")
  aamm = aamm.to_s.rjust(4, "0")
  cnpj = cnpj.to_s.delete("^0-9").rjust(14, "0")
  modelo = modelo.to_s.rjust(2, "0")
  serie = serie.to_s.rjust(3, "0")
  nNF = nNF.to_s.rjust(9, "0")
  cNF = cNF.to_s.rjust(8, "0")
  nChave = "#{uf[0,2]}#{aamm[0,4]}#{cnpj[0,14]}#{modelo[0,2]}#{serie[0,3]}#{nNF[0,9]}#{tpEmis[0,1]}#{cNF[0,8]}"
  nPesos = "4329876543298765432987654329876543298765432"
  cDV = 11 - (nChave.split("").each_with_index.map { |n, index| n.to_i * nPesos[index].to_i }.sum % 11)
  return ["#{nChave}#{cDV}", cDV]
end

#cancelarNF(chaveNF, sequenciaEvento, dataHoraEvento, numProtocolo, justificativa, idLote) ⇒ Object

Cancelar NF - Gera, assina e envia o documento com certificado A1 (exportarCancelarNF, assinarNF, enviarEvento)



297
298
299
300
301
# File 'lib/sefaz/webservice/nfe/client.rb', line 297

def cancelarNF(chaveNF, sequenciaEvento, dataHoraEvento, numProtocolo, justificativa, idLote)
  _, hash = exportarCancelarNF(chaveNF, sequenciaEvento, dataHoraEvento, numProtocolo, justificativa)
  _, hash = assinarNF(hash)
  return enviarEvento(hash, idLote)
end

#consultarCadastro(nroDocumento, tpDocumento, uf) ⇒ Object

Consulta Cadastro @nroDocumento(String) = Número do documento @tpDocumento(String) = CNPJ/CPF/IE @uf(String) = Sigla do estado que será consultado (SP; MG; RJ; …)



101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/sefaz/webservice/nfe/client.rb', line 101

def consultarCadastro(nroDocumento, tpDocumento, uf)
  versao = "2.00"
  hash = { ConsCad: { infCons: { xServ: 'CONS-CAD', UF: uf }, :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao } }
  case tpDocumento
  when 'CNPJ'; hash[:ConsCad][:infCons][:CNPJ] = nroDocumento.to_s.delete("^0-9")
  when 'CPF';  hash[:ConsCad][:infCons][:CPF]  = nroDocumento.to_s.delete("^0-9")
  when 'IE';   hash[:ConsCad][:infCons][:IE]   = nroDocumento.to_s.delete("^0-9")
  end
  wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NfeConsultaCadastro, @ambiente, @uf)
  conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
  resp = conn.call(:consulta_cadastro, hash)
  return [resp.body.to_xml!, resp.body]
end

#consultarNF(chaveNF) ⇒ Object

Consulta Situação NF @chaveNF(String) = Chave de acesso de uma NF



88
89
90
91
92
93
94
95
# File 'lib/sefaz/webservice/nfe/client.rb', line 88

def consultarNF(chaveNF)
  versao = "4.00"
  hash = { consSitNFe: { tpAmb: @ambiente, xServ: 'CONSULTAR', chNFe: chaveNF, :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao } }
  wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NfeConsultaProtocolo, @ambiente, @uf)
  conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
  resp = conn.call(:nfe_consulta_nf, hash)
  return [resp.body.to_xml!, resp.body]
end

#consultarRecibo(numRecibo) ⇒ Object

Consulta Recebido de Lote @numRecibo(String) = Número do recibo do lote de NF-e



117
118
119
120
121
122
123
124
# File 'lib/sefaz/webservice/nfe/client.rb', line 117

def consultarRecibo(numRecibo)
  versao = "4.00"
  hash = { consReciNFe: { tpAmb: @ambiente, nRec: numRecibo, :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao } }
  wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NFeRetAutorizacao, @ambiente, @uf)
  conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
  resp = conn.call(:nfe_ret_autorizacao_lote, hash)
  return [resp.body.to_xml!, resp.body]
end

#enviarCCe(chaveNF, sequenciaEvento, dataHoraEvento, textoCorrecao, idLote) ⇒ Object

Enviar CCe - Gera, assina e envia o documento com certificado A1 (exportarCCe, assinarNF, enviarEvento)



329
330
331
332
333
# File 'lib/sefaz/webservice/nfe/client.rb', line 329

def enviarCCe(chaveNF, sequenciaEvento, dataHoraEvento, textoCorrecao, idLote)
  _, hash = exportarCCe(chaveNF, sequenciaEvento, dataHoraEvento, textoCorrecao)
  _, hash = assinarNF(hash)
  return enviarEvento(hash, idLote)
end

#enviarEvento(evento, idLote) ⇒ Object

Enviar Evento - Necessário um documento assinado OBS: Recomendado quando utilizado o certificado A3 @evento(Hash ou String) = XML ou HASH assinado que será enviado @idLote(String) = Identificador de controle do Lote de envio do Evento



357
358
359
# File 'lib/sefaz/webservice/nfe/client.rb', line 357

def enviarEvento(evento, idLote)
  return enviarLoteDeEvento([ evento ], idLote)
end

#enviarInutilizarNF(documento) ⇒ Object

Enviar Inutilização NF - Necessário um documento assinado OBS: Recomendado quando utilizado o certificado A3 @documento(Hash ou String) = XML ou HASH assinado que será enviado



281
282
283
284
285
286
287
288
# File 'lib/sefaz/webservice/nfe/client.rb', line 281

def enviarInutilizarNF(documento)
  versao = "4.00"
  hash = (documento.is_a?(Hash) ? documento : documento.to_hash!)
  wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NfeInutilizacao, @ambiente, @uf)
  conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
  resp = conn.call(:nfe_inutilizacao_nf, hash)
  return [resp.body.to_xml!, resp.body]
end

#enviarLoteDeEvento(lote, idLote) ⇒ Object

Envia Lote de Eventos - Necessário que cada evento esteja assinado OBS: Recomendado quando utilizado o certificado A3 e/ou para envio em lote de eventos

Cada elemento do Array pode ser Hash ou XML assinados

@lote(Array) = Array de eventos assinados @idLote(String) = Identificador de controle do Lote de envio do Evento Exemplo de @lote: @eve1_xml, @eve1_hash = @webservice.exportarCancelarNF(…) @eve2_xml, @eve2_hash = @webservice.exportarCancelarNF(…)



370
371
372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/sefaz/webservice/nfe/client.rb', line 370

def enviarLoteDeEvento(lote, idLote)
  versao = "1.00"
  lote = (lote.map { |el| el.is_a?(Hash) ? el[:evento] : el.to_hash![:evento] })
  hash = {
    envEvento: { :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao,
      idLote: idLote,
      evento: lote
    }
  }
  wsdl = SEFAZ::Webservice::NFE::WSDL.get(:RecepcaoEvento, @ambiente, @uf)
  conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
  resp = conn.call(:nfe_recepcao_evento, hash)
  return [resp.body.to_xml!, resp.body]
end

#enviarLoteNF(lote, indSinc, idLote) ⇒ Object

Envia Lote de NF - Necessário que cada NF esteja assinada OBS: Recomendado para envio em lote de NF, cada elemento do Array pode ser Hash ou XML assinados @lote(Array) = Array de NF assinadas @indSinc(String) = “0”=Assíncrono / “1”=Síncrono @idLote(String) = Identificador de controle do Lote de envio do Lote Exemplo de @lote: @nf1_xml, @nf1_hash = @webservice.assinarNF(…) @nf2_xml, @nf2_hash = @webservice.assinarNF(…)



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/sefaz/webservice/nfe/client.rb', line 153

def enviarLoteNF(lote, indSinc, idLote)
  versao = "4.00"
  lote = (lote.map { |el| el.is_a?(Hash) ? el[:NFe] : el.to_hash![:NFe] })
  hash = {
    enviNFe: { :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao,
      idLote: idLote,
      indSinc: indSinc,
      NFe: lote
    }
  }
  wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NFeAutorizacao, @ambiente, @uf)
  conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
  resp = conn.call(:nfe_autorizacao_lote, hash)
  return [resp.body.to_xml!, resp.body]
end

#enviarNF(documento, indSinc, idLote) ⇒ Object

Enviar NF - Necessário uma NF assinada @documento(Hash ou String) = XML ou HASH assinado que será enviado @indSinc(String) = “0”=Assíncrono / “1”=Síncrono @idLote(String) = Identificador de controle do Lote de envio do Lote



140
141
142
# File 'lib/sefaz/webservice/nfe/client.rb', line 140

def enviarNF(documento, indSinc, idLote)
  return enviarLoteNF([ documento ], indSinc, idLote)
end

#exportarCancelarNF(chaveNF, sequenciaEvento, dataHoraEvento, numProtocolo, justificativa) ⇒ Object

Exportar Cancelar NF - Exporta um documento bruto (sem assinatura) OBS: Recomendado quando utilizado o certificado A3



311
312
313
314
315
316
317
318
319
320
321
# File 'lib/sefaz/webservice/nfe/client.rb', line 311

def exportarCancelarNF(chaveNF, sequenciaEvento, dataHoraEvento, numProtocolo, justificativa)
  versao = "1.00"
  tpEvento = "110111"
  _, hash  = gerarLeiauteEvento(versao, tpEvento, chaveNF, sequenciaEvento, dataHoraEvento)
  hash[:evento][:infEvento][:detEvento] = { :@versao => versao,
    descEvento: "Cancelamento",
    nProt: numProtocolo,
    xJust: justificativa
  }
  return [hash.to_xml!, hash]
end

#exportarCCe(chaveNF, sequenciaEvento, dataHoraEvento, textoCorrecao) ⇒ Object

Exportar CCe - Exporta um documento bruto (sem assinatura) OBS: Recomendado quando utilizado o certificado A3



341
342
343
344
345
346
347
348
349
350
351
# File 'lib/sefaz/webservice/nfe/client.rb', line 341

def exportarCCe(chaveNF, sequenciaEvento, dataHoraEvento, textoCorrecao)
  versao = "1.00"
  tpEvento = "110110"
  _, hash  = gerarLeiauteEvento(versao, tpEvento, chaveNF, sequenciaEvento, dataHoraEvento)
  hash[:evento][:infEvento][:detEvento] = { :@versao => versao,
    descEvento: "Carta de Correcao",
    xCorrecao: textoCorrecao,
    xCondUso: "A Carta de Correcao e disciplinada pelo paragrafo 1o-A do art. 7o do Convenio S/N, de 15 de dezembro de 1970 e pode ser utilizada para regularizacao de erro ocorrido na emissao de documento fiscal, desde que o erro nao esteja relacionado com: I - as variaveis que determinam o valor do imposto tais como: base de calculo, aliquota, diferenca de preco, quantidade, valor da operacao ou da prestacao; II - a correcao de dados cadastrais que implique mudanca do remetente ou do destinatario; III - a data de emissao ou de saida."
  }
  return [hash.to_xml!, hash]
end

#exportarInutilizarNF(chaveInut, ano, modelo, serie, nroNFIni, nroNFFin, justificativa) ⇒ Object

Exportar Inutilização NF - Exporta um documento bruto (sem assinatura) OBS: Recomendado quando utilizado o certificado A3

Caso parâmetro @chaveInut estiver em branco, a chave será calculada automaticamente (calculaChaveInutilizacao)


259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/sefaz/webservice/nfe/client.rb', line 259

def exportarInutilizarNF(chaveInut, ano, modelo, serie, nroNFIni, nroNFFin, justificativa)
  versao  = "4.00"
  chaveInut = calculaChaveInutilizacao(ano, @cnpj, modelo, serie, nroNFIni, nroNFFin) if chaveInut.blank?
  hash = { inutNFe: { :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao, infInut: {
    :@Id => chaveInut,
    tpAmb:  @ambiente,
    xServ:  'INUTILIZAR',
    cUF:    @uf,
    ano:    ano,
    CNPJ:   @cnpj,
    mod:    modelo,
    serie:  serie,
    nNFIni: nroNFIni,
    nNFFin: nroNFFin,
    xJust:  justificativa
  } } }
  return [hash.to_xml!, hash]
end

#gerarInfRespTec(documento) ⇒ Object

Gera Informações do Responsável Técnico - Calcula o hashCSRT e cria o grupo do responsável técnico Necessário quando estiver emitindo uma NF-e/NFC-e @documento(Hash ou String) = XML ou HASH que será tratado



388
389
390
391
392
393
394
395
396
397
# File 'lib/sefaz/webservice/nfe/client.rb', line 388

def gerarInfRespTec(documento)
  hash = (documento.is_a?(Hash) ? documento : documento.to_hash!)
  chaveNF = hash[:NFe][:infNFe][:@Id].to_s.delete("^0-9")
  concat = @CSRT.to_s + chaveNF.to_s
  hexdigest = Digest::SHA1.hexdigest(concat)
  hashCSRT  = Base64.strict_encode64(hexdigest)
  infRespTec = { infRespTec: { CNPJ: @cnpjTec, xContato: @contatoTec, email: @emailTec, fone: @foneTec, idCSRT: @idCSRT, hashCSRT: hashCSRT } }.compress!
  hash[:NFe][:infNFe][:infRespTec] = infRespTec[:infRespTec]
  return [hash.to_xml!, hash]
end

#inutilizarNF(chaveInut, ano, modelo, serie, nroNFIni, nroNFFin, justificativa) ⇒ Object

Inutilizar NF - Gera, assina e envia o documento com certificado A1 (exportarInutilizarNF, assinarNF, enviarInutilizarNF) OBS: Caso parâmetro @chaveInut estiver em branco, a chave será calculada automaticamente (calculaChaveInutilizacao)



229
230
231
232
233
# File 'lib/sefaz/webservice/nfe/client.rb', line 229

def inutilizarNF(chaveInut, ano, modelo, serie, nroNFIni, nroNFFin, justificativa)
  _, hash = exportarInutilizarNF(chaveInut, ano, modelo, serie, nroNFIni, nroNFFin, justificativa)
  _, hash = assinarNF(hash)
  return enviarInutilizarNF(hash)
end

#setaAmbiente(params = {}) ⇒ Object



53
54
55
56
57
# File 'lib/sefaz/webservice/nfe/client.rb', line 53

def setaAmbiente(params = {})
  @uf = params[:uf]
  @ambiente = params[:ambiente]
  @cnpj = params[:cnpj].to_s.delete("^0-9")
end

#setaPFXAss(params = {}) ⇒ Object



72
73
74
# File 'lib/sefaz/webservice/nfe/client.rb', line 72

def setaPFXAss(params = {})
  @pkcs12Ass = OpenSSL::PKCS12.new(params[:pfx], params[:senha])
end

#setaPFXTss(params = {}) ⇒ Object



68
69
70
# File 'lib/sefaz/webservice/nfe/client.rb', line 68

def setaPFXTss(params = {})
  @pkcs12Tss = OpenSSL::PKCS12.new(params[:pfx], params[:senha])
end

#setaRespTecnico(params = {}) ⇒ Object



59
60
61
62
63
64
65
66
# File 'lib/sefaz/webservice/nfe/client.rb', line 59

def setaRespTecnico(params = {})
  @cnpjTec = params[:cnpj]
  @contatoTec = params[:contato]
  @emailTec = params[:email]
  @foneTec = params[:fone]
  @idCSRT = params[:idCSRT]
  @CSRT = params[:CSRT]
end

#statusDoServicoObject

Consulta Status SEFAZ



77
78
79
80
81
82
83
84
# File 'lib/sefaz/webservice/nfe/client.rb', line 77

def statusDoServico
  versao = "4.00"
  hash = { consStatServ: { tpAmb: @ambiente, cUF: @uf, xServ: 'STATUS', :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao } }
  wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NfeStatusServico, @ambiente, @uf)
  conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
  resp = conn.call(:nfe_status_servico_nf, hash)
  return [resp.body.to_xml!, resp.body]
end

#validarNF(documento, openTimeout = 60, readTimeout = 60) ⇒ Object

Valida NF no SEFAZ RS NF-e (www.sefaz.rs.gov.br/NFE/NFE-VAL.aspx) @documento(Hash ou String) = XML ou HASH que será validado @openTimeout(Integer) = Tempo de espera em segundos para abrir conexão (opcional: padrão 60) @readTimeout(Integer) = Tempo de espera em segundos para ler resposta (opcional: padrão 60)



196
197
198
199
200
201
202
203
204
# File 'lib/sefaz/webservice/nfe/client.rb', line 196

def validarNF(documento, openTimeout = 60, readTimeout = 60)
  xml = (documento.is_a?(Hash) ? documento.to_xml! : documento)
  validator = SEFAZ::Webservice::NFE::Validator.new(xml)
  stat, msg, err = validator.exec(openTimeout, readTimeout)
  case stat
  when :ok; return [true, msg, err]
  else      return [false, {}, {}]
  end
end