sefaz 0.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +115 -0
  3. data/Gemfile.lock +31 -17
  4. data/README.md +449 -17
  5. data/Rakefile +1 -0
  6. data/docs/CFe-SAT/Especificacao_SAT_v_ER_2_30_03.pdf +0 -0
  7. data/docs/CFe-SAT/Manual_Orientacao_SAT_v_MO_2_19_04.pdf +0 -0
  8. data/docs/CFe-SAT/Manual_do_Emulador_SAT-CF-e_Offline_2015_09_10.pdf +0 -0
  9. data/docs/CFe-SAT/_CANCEL_dataset.md +14 -0
  10. data/docs/CFe-SAT/_SALE_dataset.md +171 -0
  11. data/docs/CFe-SAT/emulador_off_line_v2_9_4.zip +0 -0
  12. data/docs/NFe-NFCe/ANEXO I - Leiaute e Regra de Valida/303/247/303/243o - NF-e e NFC-e.pdf +0 -0
  13. data/docs/NFe-NFCe/ANEXO II -Manual Especifica/303/247/303/265esT/303/251cnicas - Danfe-C/303/263digo-Barras.pdf +0 -0
  14. data/docs/NFe-NFCe/Anexo III - Manual de Conting/303/252ncia - NF-e.pdf +0 -0
  15. data/docs/NFe-NFCe/Anexo IV - Manual de Conting/303/252ncia - NFC-e.pdf +0 -0
  16. data/docs/NFe-NFCe/Manual de Orienta/303/247/303/243o ao Contribuinte - MOC - vers/303/243o 7.0 - NF-e e NFC-e.pdf +0 -0
  17. data/docs/NFe-NFCe/_dataset.md +819 -0
  18. data/lib/sefaz/base.rb +11 -0
  19. data/lib/sefaz/configuration.rb +58 -0
  20. data/lib/sefaz/exception.rb +14 -0
  21. data/lib/sefaz/refinement.rb +91 -0
  22. data/lib/sefaz/utils/connection.rb +35 -0
  23. data/lib/sefaz/utils/prawn_helper.rb +47 -0
  24. data/lib/sefaz/utils/signer.rb +122 -0
  25. data/lib/sefaz/version.rb +1 -1
  26. data/lib/sefaz/webservice/base.rb +13 -0
  27. data/lib/sefaz/webservice/nfe/auditor.rb +35 -0
  28. data/lib/sefaz/webservice/nfe/client.rb +426 -0
  29. data/lib/sefaz/webservice/nfe/connection.rb +17 -0
  30. data/lib/sefaz/webservice/nfe/dataset.rb +451 -0
  31. data/lib/sefaz/webservice/nfe/validator.rb +63 -0
  32. data/lib/sefaz/webservice/nfe/wsdl.rb +117 -0
  33. data/lib/sefaz/webservice/sat/client.rb +44 -0
  34. data/lib/sefaz/webservice/sat/dataset/cancel.rb +34 -0
  35. data/lib/sefaz/webservice/sat/dataset/sale.rb +176 -0
  36. data/lib/sefaz/webservice/sat/templates/base.rb +54 -0
  37. data/lib/sefaz/webservice/sat/templates/cupom_fiscal_55mm.rb +307 -0
  38. data/lib/sefaz/webservice/sat/templates/cupom_fiscal_80mm.rb +307 -0
  39. data/lib/sefaz.rb +45 -3
  40. data/sefaz.gemspec +5 -3
  41. metadata +80 -6
@@ -0,0 +1,426 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Webservice
5
+ module NFE
6
+ # Principal classe de integração com o módulo NF-e/NFC-e
7
+ class Client < SEFAZ::Webservice::Base
8
+
9
+ SERVICES = %i[ setaAmbiente setaRespTecnico setaPFXTss setaPFXAss statusDoServico consultarNF consultarCadastro consultarRecibo
10
+ assinarNF validarNF auditarNF inutilizarNF exportarInutilizarNF enviarInutilizarNF calculaChaveInutilizacao
11
+ enviarEvento enviarLoteDeEvento cancelarNF exportarCancelarNF enviarCCe exportarCCe enviarNF enviarLoteNF calculaChaveNF]
12
+
13
+ # Métodos de Configuração:
14
+ # - setaAmbiente
15
+ # - setaRespTecnico
16
+ # - setaPFXTss
17
+ # - setaPFXAss
18
+
19
+ # Métodos de Consulta, Validação e Documentos: (SEM ASSINATURA)
20
+ # - statusDoServico
21
+ # - consultarNF
22
+ # - consultarCadastro
23
+ # - consultarRecibo
24
+ # - consultarGTIN (PENDENTE)
25
+ # - consultarDistribuicaoDFe (PENDENTE)
26
+ # - consultarDistribuicaoDFeChave (PENDENTE)
27
+ # - validarNF
28
+ # - auditarNF
29
+
30
+ # Métodos de Manipulação: (MAIORIA EXIGE ASSINATURA)
31
+ # -- Os métodos 'enviarNF' e 'enviarLoteNF' não precisa 'exportar', pois os dados são montados externo à gema (XML ou Hash ou Dataset)
32
+ # - assinarNF
33
+ # - enviarNF
34
+ # - enviarLoteNF
35
+ # - calculaChaveNF
36
+ # - inutilizarNF
37
+ # - exportarInutilizarNF
38
+ # - enviarInutilizarNF
39
+ # - calculaChaveInutilizacao
40
+ # - cancelarNF (EVENTO)
41
+ # - exportarCancelarNF (EVENTO)
42
+ # - enviarCCe (EVENTO)
43
+ # - exportarCCe (EVENTO)
44
+ # - enviarManifestacao (PENDENTE) (EVENTO)
45
+ # - exportarManifestacao (PENDENTE) (EVENTO)
46
+ # - enviarEvento
47
+ # - enviarLoteDeEvento
48
+ # - gerarLeiauteEvento (PRIVADO)
49
+
50
+ def initialize
51
+ end
52
+
53
+ def setaAmbiente(params = {})
54
+ @uf = params[:uf]
55
+ @ambiente = params[:ambiente]
56
+ @cnpj = params[:cnpj].to_s.delete("^0-9")
57
+ end
58
+
59
+ def setaRespTecnico(params = {})
60
+ @cnpjTec = params[:cnpj]
61
+ @contatoTec = params[:contato]
62
+ @emailTec = params[:email]
63
+ @foneTec = params[:fone]
64
+ @idCSRT = params[:idCSRT]
65
+ @CSRT = params[:CSRT]
66
+ end
67
+
68
+ def setaPFXTss(params = {})
69
+ @pkcs12Tss = OpenSSL::PKCS12.new(params[:pfx], params[:senha])
70
+ end
71
+
72
+ def setaPFXAss(params = {})
73
+ @pkcs12Ass = OpenSSL::PKCS12.new(params[:pfx], params[:senha])
74
+ end
75
+
76
+ # Consulta Status SEFAZ
77
+ def statusDoServico
78
+ versao = "4.00"
79
+ hash = { consStatServ: { tpAmb: @ambiente, cUF: @uf, xServ: 'STATUS', :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao } }
80
+ wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NfeStatusServico, @ambiente, @uf)
81
+ conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
82
+ resp = conn.call(:nfe_status_servico_nf, hash)
83
+ return [resp.body.to_xml!, resp.body]
84
+ end
85
+
86
+ # Consulta Situação NF
87
+ # @chaveNF(String) = Chave de acesso de uma NF
88
+ def consultarNF(chaveNF)
89
+ versao = "4.00"
90
+ hash = { consSitNFe: { tpAmb: @ambiente, xServ: 'CONSULTAR', chNFe: chaveNF, :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao } }
91
+ wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NfeConsultaProtocolo, @ambiente, @uf)
92
+ conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
93
+ resp = conn.call(:nfe_consulta_nf, hash)
94
+ return [resp.body.to_xml!, resp.body]
95
+ end
96
+
97
+ # Consulta Cadastro
98
+ # @nroDocumento(String) = Número do documento
99
+ # @tpDocumento(String) = CNPJ/CPF/IE
100
+ # @uf(String) = Sigla do estado que será consultado (SP; MG; RJ; ...)
101
+ def consultarCadastro(nroDocumento, tpDocumento, uf)
102
+ versao = "2.00"
103
+ hash = { ConsCad: { infCons: { xServ: 'CONS-CAD', UF: uf }, :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao } }
104
+ case tpDocumento
105
+ when 'CNPJ'; hash[:ConsCad][:infCons][:CNPJ] = nroDocumento.to_s.delete("^0-9")
106
+ when 'CPF'; hash[:ConsCad][:infCons][:CPF] = nroDocumento.to_s.delete("^0-9")
107
+ when 'IE'; hash[:ConsCad][:infCons][:IE] = nroDocumento.to_s.delete("^0-9")
108
+ end
109
+ wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NfeConsultaCadastro, @ambiente, @uf)
110
+ conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
111
+ resp = conn.call(:consulta_cadastro, hash)
112
+ return [resp.body.to_xml!, resp.body]
113
+ end
114
+
115
+ # Consulta Recebido de Lote
116
+ # @numRecibo(String) = Número do recibo do lote de NF-e
117
+ def consultarRecibo(numRecibo)
118
+ versao = "4.00"
119
+ hash = { consReciNFe: { tpAmb: @ambiente, nRec: numRecibo, :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao } }
120
+ wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NFeRetAutorizacao, @ambiente, @uf)
121
+ conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
122
+ resp = conn.call(:nfe_ret_autorizacao_lote, hash)
123
+ return [resp.body.to_xml!, resp.body]
124
+ end
125
+
126
+ # Assinar NF - PFX de assinatura - Certificado A1
127
+ # @documento(Hash ou String) = XML ou HASH que será assinado
128
+ def assinarNF(documento)
129
+ xml = (documento.is_a?(Hash) ? documento.to_xml! : documento)
130
+ doc = SEFAZ::Utils::Signer.new(xml)
131
+ doc.sign!(@pkcs12Ass.certificate, @pkcs12Ass.key)
132
+ xml = doc.to_xml
133
+ return [xml, xml.to_hash!]
134
+ end
135
+
136
+ # Enviar NF - Necessário uma NF assinada
137
+ # @documento(Hash ou String) = XML ou HASH assinado que será enviado
138
+ # @indSinc(String) = "0"=Assíncrono / "1"=Síncrono
139
+ # @idLote(String) = Identificador de controle do Lote de envio do Lote
140
+ def enviarNF(documento, indSinc, idLote)
141
+ return enviarLoteNF([ documento ], indSinc, idLote)
142
+ end
143
+
144
+ # Envia Lote de NF - Necessário que cada NF esteja assinada
145
+ # OBS: Recomendado para envio em lote de NF, cada elemento do Array pode ser Hash ou XML assinados
146
+ # @lote(Array) = Array de NF assinadas
147
+ # @indSinc(String) = "0"=Assíncrono / "1"=Síncrono
148
+ # @idLote(String) = Identificador de controle do Lote de envio do Lote
149
+ # Exemplo de @lote:
150
+ # @nf1_xml, @nf1_hash = @webservice.assinarNF(...)
151
+ # @nf2_xml, @nf2_hash = @webservice.assinarNF(...)
152
+ # @lote = [ @nf1_xml, @nf2_hash ]
153
+ def enviarLoteNF(lote, indSinc, idLote)
154
+ versao = "4.00"
155
+ lote = (lote.map { |el| el.is_a?(Hash) ? el[:NFe] : el.to_hash![:NFe] })
156
+ hash = {
157
+ enviNFe: { :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao,
158
+ idLote: idLote,
159
+ indSinc: indSinc,
160
+ NFe: lote
161
+ }
162
+ }
163
+ wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NFeAutorizacao, @ambiente, @uf)
164
+ conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
165
+ resp = conn.call(:nfe_autorizacao_lote, hash)
166
+ return [resp.body.to_xml!, resp.body]
167
+ end
168
+
169
+ # Calcular Chave NF
170
+ # @uf = Código da UF do emitente do Documento Fiscal
171
+ # @aamm = Ano e Mês de emissão da NF-e
172
+ # @cnpj = CNPJ do emitente
173
+ # @modelo = Modelo do Documento Fiscal (55 ou 65)
174
+ # @serie = Série do Documento Fiscal
175
+ # @nNF = Número do Documento Fiscal
176
+ # @tpEmis = Forma de emissão da NF-e
177
+ # @cNF = Código Numérico que compõe a Chave de Acesso (ID do sistema)
178
+ def calculaChaveNF(uf, aamm, cnpj, modelo, serie, nNF, tpEmis, cNF)
179
+ uf = uf.to_s.rjust(2, "0")
180
+ aamm = aamm.to_s.rjust(4, "0")
181
+ cnpj = cnpj.to_s.delete("^0-9").rjust(14, "0")
182
+ modelo = modelo.to_s.rjust(2, "0")
183
+ serie = serie.to_s.rjust(3, "0")
184
+ nNF = nNF.to_s.rjust(9, "0")
185
+ cNF = cNF.to_s.rjust(8, "0")
186
+ 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]}"
187
+ nPesos = "4329876543298765432987654329876543298765432"
188
+ cDV = 11 - (nChave.split("").each_with_index.map { |n, index| n.to_i * nPesos[index].to_i }.sum % 11)
189
+ return ["#{nChave}#{cDV}", cDV]
190
+ end
191
+
192
+ # Valida NF no SEFAZ RS NF-e (https://www.sefaz.rs.gov.br/NFE/NFE-VAL.aspx)
193
+ # @documento(Hash ou String) = XML ou HASH que será validado
194
+ # @openTimeout(Integer) = Tempo de espera em segundos para abrir conexão (opcional: padrão 60)
195
+ # @readTimeout(Integer) = Tempo de espera em segundos para ler resposta (opcional: padrão 60)
196
+ def validarNF(documento, openTimeout = 60, readTimeout = 60)
197
+ xml = (documento.is_a?(Hash) ? documento.to_xml! : documento)
198
+ validator = SEFAZ::Webservice::NFE::Validator.new(xml)
199
+ stat, msg, err = validator.exec(openTimeout, readTimeout)
200
+ case stat
201
+ when :ok; return [true, msg, err]
202
+ else return [false, {}, {}]
203
+ end
204
+ end
205
+
206
+ # Auditar NF no validador TecnoSpeed (https://validador.nfe.tecnospeed.com.br/)
207
+ # @documento(Hash ou String) = XML ou HASH que será auditado
208
+ # @openTimeout(Integer) = Tempo de espera em segundos para abrir conexão (opcional: padrão 60)
209
+ # @readTimeout(Integer) = Tempo de espera em segundos para ler resposta (opcional: padrão 60)
210
+ def auditarNF(documento, openTimeout = 60, readTimeout = 60)
211
+ xml = (documento.is_a?(Hash) ? documento.to_xml! : documento)
212
+ auditor = SEFAZ::Webservice::NFE::Auditor.new(xml)
213
+ stat, msg = auditor.exec(openTimeout, readTimeout)
214
+ case stat
215
+ when :ok; return [true, msg]
216
+ else return [false, {}]
217
+ end
218
+ end
219
+
220
+ # Inutilizar NF - Gera, assina e envia o documento com certificado A1 (exportarInutilizarNF, assinarNF, enviarInutilizarNF)
221
+ # OBS: Caso parâmetro @chaveInut estiver em branco, a chave será calculada automaticamente (calculaChaveInutilizacao)
222
+ # @chaveInut = Identificador da TAG a ser assinada
223
+ # @ano = Ano de inutilização da numeração
224
+ # @modelo = Modelo do documento (55 ou 65)
225
+ # @serie = Série da NF-e
226
+ # @nroNFIni = Número da NF-e inicial a ser inutilizada
227
+ # @nroNFFin = Número da NF-e final a ser inutilizada
228
+ # @justificativa = Informar a justificativa do pedido de inutilização
229
+ def inutilizarNF(chaveInut, ano, modelo, serie, nroNFIni, nroNFFin, justificativa)
230
+ _, hash = exportarInutilizarNF(chaveInut, ano, modelo, serie, nroNFIni, nroNFFin, justificativa)
231
+ _, hash = assinarNF(hash)
232
+ return enviarInutilizarNF(hash)
233
+ end
234
+
235
+ # Calcular Chave de Inutilização
236
+ # @ano = Ano de inutilização da numeração
237
+ # @cnpj = CNPJ do emitente
238
+ # @modelo = Modelo do documento (55 ou 65)
239
+ # @serie = Série da NF-e
240
+ # @nroNFIni = Número da NF-e inicial a ser inutilizada
241
+ # @nroNFFin = Número da NF-e final a ser inutilizada
242
+ def calculaChaveInutilizacao(ano, cnpj, modelo, serie, nroNFIni, nroNFFin)
243
+ serie = serie.to_s.rjust(3, "0")
244
+ nroNFIni = nroNFIni.to_s.rjust(9, "0")
245
+ nroNFFin = nroNFFin.to_s.rjust(9, "0")
246
+ return "ID#{@uf}#{ano}#{cnpj}#{modelo}#{serie}#{nroNFIni}#{nroNFFin}"
247
+ end
248
+
249
+ # Exportar Inutilização NF - Exporta um documento bruto (sem assinatura)
250
+ # OBS: Recomendado quando utilizado o certificado A3
251
+ # Caso parâmetro @chaveInut estiver em branco, a chave será calculada automaticamente (calculaChaveInutilizacao)
252
+ # @chaveInut = Identificador da TAG a ser assinada
253
+ # @ano = Ano de inutilização da numeração
254
+ # @modelo = Modelo do documento (55 ou 65)
255
+ # @serie = Série da NF-e
256
+ # @nroNFIni = Número da NF-e inicial a ser inutilizada
257
+ # @nroNFFin = Número da NF-e final a ser inutilizada
258
+ # @justificativa = Informar a justificativa do pedido de inutilização
259
+ def exportarInutilizarNF(chaveInut, ano, modelo, serie, nroNFIni, nroNFFin, justificativa)
260
+ versao = "4.00"
261
+ chaveInut = calculaChaveInutilizacao(ano, @cnpj, modelo, serie, nroNFIni, nroNFFin) if chaveInut.blank?
262
+ hash = { inutNFe: { :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao, infInut: {
263
+ :@Id => chaveInut,
264
+ tpAmb: @ambiente,
265
+ xServ: 'INUTILIZAR',
266
+ cUF: @uf,
267
+ ano: ano,
268
+ CNPJ: @cnpj,
269
+ mod: modelo,
270
+ serie: serie,
271
+ nNFIni: nroNFIni,
272
+ nNFFin: nroNFFin,
273
+ xJust: justificativa
274
+ } } }
275
+ return [hash.to_xml!, hash]
276
+ end
277
+
278
+ # Enviar Inutilização NF - Necessário um documento assinado
279
+ # OBS: Recomendado quando utilizado o certificado A3
280
+ # @documento(Hash ou String) = XML ou HASH assinado que será enviado
281
+ def enviarInutilizarNF(documento)
282
+ versao = "4.00"
283
+ hash = (documento.is_a?(Hash) ? documento : documento.to_hash!)
284
+ wsdl = SEFAZ::Webservice::NFE::WSDL.get(:NfeInutilizacao, @ambiente, @uf)
285
+ conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
286
+ resp = conn.call(:nfe_inutilizacao_nf, hash)
287
+ return [resp.body.to_xml!, resp.body]
288
+ end
289
+
290
+ # Cancelar NF - Gera, assina e envia o documento com certificado A1 (exportarCancelarNF, assinarNF, enviarEvento)
291
+ # @chaveNF = Chave de acesso de uma NF
292
+ # @sequenciaEvento = O número do evento
293
+ # @dataHoraEvento = Data e Hora da Emissão do Evento (ex: 2023-01-15T17:23:00+03:00)
294
+ # @numProtocolo = Número do Protocolo de registro da NF
295
+ # @justificativa = Motivo do cancelamento da NF
296
+ # @idLote = Número de controle interno
297
+ def cancelarNF(chaveNF, sequenciaEvento, dataHoraEvento, numProtocolo, justificativa, idLote)
298
+ _, hash = exportarCancelarNF(chaveNF, sequenciaEvento, dataHoraEvento, numProtocolo, justificativa)
299
+ _, hash = assinarNF(hash)
300
+ return enviarEvento(hash, idLote)
301
+ end
302
+
303
+ # Exportar Cancelar NF - Exporta um documento bruto (sem assinatura)
304
+ # OBS: Recomendado quando utilizado o certificado A3
305
+ # @chaveNF = Chave de acesso de uma NF
306
+ # @sequenciaEvento = O número do evento
307
+ # @dataHoraEvento = Data e Hora da Emissão do Evento (ex: 2023-01-15T17:23:00+03:00)
308
+ # @numProtocolo = Número do Protocolo de registro da NF
309
+ # @justificativa = Motivo do cancelamento da NF
310
+ # @idLote = Número de controle interno
311
+ def exportarCancelarNF(chaveNF, sequenciaEvento, dataHoraEvento, numProtocolo, justificativa)
312
+ versao = "1.00"
313
+ tpEvento = "110111"
314
+ _, hash = gerarLeiauteEvento(versao, tpEvento, chaveNF, sequenciaEvento, dataHoraEvento)
315
+ hash[:evento][:infEvento][:detEvento] = { :@versao => versao,
316
+ descEvento: "Cancelamento",
317
+ nProt: numProtocolo,
318
+ xJust: justificativa
319
+ }
320
+ return [hash.to_xml!, hash]
321
+ end
322
+
323
+ # Enviar CCe - Gera, assina e envia o documento com certificado A1 (exportarCCe, assinarNF, enviarEvento)
324
+ # @chaveNF = Chave de acesso de uma NF
325
+ # @sequenciaEvento = O número do evento
326
+ # @dataHoraEvento = Data e Hora da Emissão do Evento (ex: 2023-01-15T17:23:00+03:00)
327
+ # @textoCorrecao = Motivo do cancelamento da NF
328
+ # @idLote = Número de controle interno
329
+ def enviarCCe(chaveNF, sequenciaEvento, dataHoraEvento, textoCorrecao, idLote)
330
+ _, hash = exportarCCe(chaveNF, sequenciaEvento, dataHoraEvento, textoCorrecao)
331
+ _, hash = assinarNF(hash)
332
+ return enviarEvento(hash, idLote)
333
+ end
334
+
335
+ # Exportar CCe - Exporta um documento bruto (sem assinatura)
336
+ # OBS: Recomendado quando utilizado o certificado A3
337
+ # @chaveNF = Chave de acesso de uma NF
338
+ # @sequenciaEvento = O número do evento
339
+ # @dataHoraEvento = Data e Hora da Emissão do Evento (ex: 2023-01-15T17:23:00+03:00)
340
+ # @textoCorrecao = Motivo do cancelamento da NF
341
+ def exportarCCe(chaveNF, sequenciaEvento, dataHoraEvento, textoCorrecao)
342
+ versao = "1.00"
343
+ tpEvento = "110110"
344
+ _, hash = gerarLeiauteEvento(versao, tpEvento, chaveNF, sequenciaEvento, dataHoraEvento)
345
+ hash[:evento][:infEvento][:detEvento] = { :@versao => versao,
346
+ descEvento: "Carta de Correcao",
347
+ xCorrecao: textoCorrecao,
348
+ 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."
349
+ }
350
+ return [hash.to_xml!, hash]
351
+ end
352
+
353
+ # Enviar Evento - Necessário um documento assinado
354
+ # OBS: Recomendado quando utilizado o certificado A3
355
+ # @evento(Hash ou String) = XML ou HASH assinado que será enviado
356
+ # @idLote(String) = Identificador de controle do Lote de envio do Evento
357
+ def enviarEvento(evento, idLote)
358
+ return enviarLoteDeEvento([ evento ], idLote)
359
+ end
360
+
361
+ # Envia Lote de Eventos - Necessário que cada evento esteja assinado
362
+ # OBS: Recomendado quando utilizado o certificado A3 e/ou para envio em lote de eventos
363
+ # Cada elemento do Array pode ser Hash ou XML assinados
364
+ # @lote(Array) = Array de eventos assinados
365
+ # @idLote(String) = Identificador de controle do Lote de envio do Evento
366
+ # Exemplo de @lote:
367
+ # @eve1_xml, @eve1_hash = @webservice.exportarCancelarNF(...)
368
+ # @eve2_xml, @eve2_hash = @webservice.exportarCancelarNF(...)
369
+ # @lote = [ @eve1_xml, @eve2_hash ]
370
+ def enviarLoteDeEvento(lote, idLote)
371
+ versao = "1.00"
372
+ lote = (lote.map { |el| el.is_a?(Hash) ? el[:evento] : el.to_hash![:evento] })
373
+ hash = {
374
+ envEvento: { :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao,
375
+ idLote: idLote,
376
+ evento: lote
377
+ }
378
+ }
379
+ wsdl = SEFAZ::Webservice::NFE::WSDL.get(:RecepcaoEvento, @ambiente, @uf)
380
+ conn = SEFAZ::Webservice::NFE::Connection.new(@pkcs12Tss, wsdl, versao, @uf)
381
+ resp = conn.call(:nfe_recepcao_evento, hash)
382
+ return [resp.body.to_xml!, resp.body]
383
+ end
384
+
385
+ # Gera Informações do Responsável Técnico - Calcula o hashCSRT e cria o grupo do responsável técnico
386
+ # Necessário quando estiver emitindo uma NF-e/NFC-e
387
+ # @documento(Hash ou String) = XML ou HASH que será tratado
388
+ def gerarInfRespTec(documento)
389
+ hash = (documento.is_a?(Hash) ? documento : documento.to_hash!)
390
+ chaveNF = hash[:NFe][:infNFe][:@Id].to_s.delete("^0-9")
391
+ concat = @CSRT.to_s + chaveNF.to_s
392
+ hexdigest = Digest::SHA1.hexdigest(concat)
393
+ hashCSRT = Base64.strict_encode64(hexdigest)
394
+ infRespTec = { infRespTec: { CNPJ: @cnpjTec, xContato: @contatoTec, email: @emailTec, fone: @foneTec, idCSRT: @idCSRT, hashCSRT: hashCSRT } }.compress!
395
+ hash[:NFe][:infNFe][:infRespTec] = infRespTec[:infRespTec]
396
+ return [hash.to_xml!, hash]
397
+ end
398
+
399
+ private
400
+
401
+ # Gera o Leiaute Mensagem de Entrada (Parte Geral) dos Eventos
402
+ # Utilizado internamente nos métodos: exportarCancelarNF, exportarCCe, exportarManifestacao, ... (métodos de eventos)
403
+ def gerarLeiauteEvento(verEvento, tpEvento, chaveNF, sequenciaEvento, dataHoraEvento)
404
+ versao = "1.00"
405
+ id = "ID" + tpEvento.to_s + chaveNF.to_s + sequenciaEvento.to_s.rjust(2, "0")
406
+ hash = {
407
+ evento: { :@xmlns => "http://www.portalfiscal.inf.br/nfe", :@versao => versao,
408
+ infEvento: { :@Id => id,
409
+ cOrgao: @uf,
410
+ tpAmb: @ambiente,
411
+ CNPJ: @cnpj,
412
+ chNFe: chaveNF,
413
+ dhEvento: dataHoraEvento,
414
+ tpEvento: tpEvento,
415
+ nSeqEvento: sequenciaEvento,
416
+ verEvento: verEvento
417
+ }
418
+ }
419
+ }
420
+ return [hash.to_xml!, hash]
421
+ end
422
+
423
+ end
424
+ end
425
+ end
426
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Webservice
5
+ module NFE
6
+ # Principal classe de conexão SOAP com o módulo NF-e/NFC-e
7
+ class Connection < SEFAZ::Utils::Connection
8
+
9
+ def initialize(pkcs12, wsdl, versaoDados, cUF)
10
+ @soap_header = { nfeCabecMsg: { versaoDados: versaoDados, cUF: cUF, :@xmlns => 'http://www.portalfiscal.inf.br/nfe' } }
11
+ super(pkcs12, wsdl, @soap_header)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end