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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +115 -0
- data/Gemfile.lock +31 -17
- data/README.md +449 -17
- data/Rakefile +1 -0
- data/docs/CFe-SAT/Especificacao_SAT_v_ER_2_30_03.pdf +0 -0
- data/docs/CFe-SAT/Manual_Orientacao_SAT_v_MO_2_19_04.pdf +0 -0
- data/docs/CFe-SAT/Manual_do_Emulador_SAT-CF-e_Offline_2015_09_10.pdf +0 -0
- data/docs/CFe-SAT/_CANCEL_dataset.md +14 -0
- data/docs/CFe-SAT/_SALE_dataset.md +171 -0
- data/docs/CFe-SAT/emulador_off_line_v2_9_4.zip +0 -0
- data/docs/NFe-NFCe/ANEXO I - Leiaute e Regra de Valida/303/247/303/243o - NF-e e NFC-e.pdf +0 -0
- data/docs/NFe-NFCe/ANEXO II -Manual Especifica/303/247/303/265esT/303/251cnicas - Danfe-C/303/263digo-Barras.pdf +0 -0
- data/docs/NFe-NFCe/Anexo III - Manual de Conting/303/252ncia - NF-e.pdf +0 -0
- data/docs/NFe-NFCe/Anexo IV - Manual de Conting/303/252ncia - NFC-e.pdf +0 -0
- 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
- data/docs/NFe-NFCe/_dataset.md +819 -0
- data/lib/sefaz/base.rb +11 -0
- data/lib/sefaz/configuration.rb +58 -0
- data/lib/sefaz/exception.rb +14 -0
- data/lib/sefaz/refinement.rb +91 -0
- data/lib/sefaz/utils/connection.rb +35 -0
- data/lib/sefaz/utils/prawn_helper.rb +47 -0
- data/lib/sefaz/utils/signer.rb +122 -0
- data/lib/sefaz/version.rb +1 -1
- data/lib/sefaz/webservice/base.rb +13 -0
- data/lib/sefaz/webservice/nfe/auditor.rb +35 -0
- data/lib/sefaz/webservice/nfe/client.rb +426 -0
- data/lib/sefaz/webservice/nfe/connection.rb +17 -0
- data/lib/sefaz/webservice/nfe/dataset.rb +451 -0
- data/lib/sefaz/webservice/nfe/validator.rb +63 -0
- data/lib/sefaz/webservice/nfe/wsdl.rb +117 -0
- data/lib/sefaz/webservice/sat/client.rb +44 -0
- data/lib/sefaz/webservice/sat/dataset/cancel.rb +34 -0
- data/lib/sefaz/webservice/sat/dataset/sale.rb +176 -0
- data/lib/sefaz/webservice/sat/templates/base.rb +54 -0
- data/lib/sefaz/webservice/sat/templates/cupom_fiscal_55mm.rb +307 -0
- data/lib/sefaz/webservice/sat/templates/cupom_fiscal_80mm.rb +307 -0
- data/lib/sefaz.rb +45 -3
- data/sefaz.gemspec +5 -3
- 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
|