inovadora_xml 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -1,5 +1,4 @@
1
1
  # coding: utf-8
2
-
3
2
  lib = File.expand_path("../lib", __FILE__)
4
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
4
  require "inovadora_xml/version"
@@ -15,6 +14,7 @@ Gem::Specification.new do |spec|
15
14
 
16
15
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
16
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+
18
18
  end
19
19
  spec.bindir = "exe"
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -23,7 +23,8 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.17"
25
25
  spec.add_development_dependency "rake", "~> 10.0"
26
- spec.add_development_dependency "nokogiri", "1.6.0"
27
26
  spec.add_development_dependency "signer", "1.4.2"
28
- spec.add_development_dependency "savon", "1.2.0"
27
+ spec.add_dependency "nokogiri", ">= 1.4.0"
28
+ spec.add_dependency "savon", "1.2.0"
29
+ spec.add_dependency "wasabi", "2.5.0"
29
30
  end
@@ -1,6 +1,97 @@
1
+ #encoding: utf-8
2
+ require 'action_pack'
3
+
1
4
  require "inovadora_xml/version"
2
5
 
6
+ require "inovadora_xml/assinador"
7
+ require "inovadora_xml/servidor_wsdl"
8
+
9
+
3
10
  module InovadoraXml
4
- class Error < StandardError; end
5
- # Your code goes here...
11
+ extend ActiveSupport::Autoload
12
+ attr_accessor :xml_nfse, :schema, :metodo_soap, :xml_gerado, :retorno, :wsdl, :cert, :key, :errors
13
+ autoload :Modules
14
+ autoload :CustomExceptions
15
+
16
+ class Xml
17
+ attr_accessor :xml_nfse, :schema, :metodo_soap, :xml_gerado, :retorno, :wsdl, :cert, :key, :errors
18
+
19
+ include InovadoraXml::Modules::FormatadorNfse
20
+ include InovadoraXml::Modules::GeradorXml
21
+
22
+ def initialize(*args)
23
+ self.errors = ActiveModel::Errors.new(self)
24
+ self.xml_gerado = self.gerar_xml()
25
+
26
+ self.validar_args()
27
+ # self.valid?
28
+ end
29
+
30
+ def comunicar(request_args = {})
31
+ if self.valid?
32
+ servidor = InovadoraXml::ServidorWsdl.new(
33
+ self.envelopar(),
34
+ self.metodo_soap,
35
+ self.wsdl,
36
+ self.cert,
37
+ self.key,
38
+ request_args
39
+ )
40
+
41
+ unless servidor.enviar
42
+ raise InovadoraXml::CustomExceptions::ServerError.new(servidor), "Server Error"
43
+ end
44
+ #usage: self.retorno.to_xml ou self.retorno.body
45
+ self.retorno = servidor.retorno
46
+ end
47
+
48
+ rescue InovadoraXml::CustomExceptions::ServerError => e
49
+ e.object.errors.full_messages.each {|e| "Erro na comunicação: #{self.errors.add(:base, e)}"}
50
+ rescue Exception => e
51
+ self.errors.add(:base, e.message)
52
+ ensure
53
+ return self.errors.blank?
54
+ end
55
+
56
+ def validar_args
57
+ self.errors.add(:base, "Metodo SOAP não especificado") if self.metodo_soap.blank?
58
+ self.errors.add(:base, "Schema não especificado") if self.schema.blank?
59
+ self.errors.add(:base, "WSDL não especificado") if self.wsdl.blank?
60
+
61
+ return self.errors.blank?
62
+ end
63
+
64
+ def valid?
65
+ erros = []
66
+ schema = open(self.schema)
67
+ xsd = Nokogiri::XML::Schema(schema)
68
+ xsd.validate(self.xml_gerado).each do |error|
69
+ unless error.message.to_s.include?("{http://www.w3.org/2000/09/xmldsig#}Signature") ||
70
+ error.message.to_s.include?("{http://www.w3.org/2000/09/xmldsig#}SignedInfo")
71
+ erros << "(Linha: " + error.line.to_s + ") => " + error.message.to_s
72
+ end
73
+ end
74
+
75
+ erros.each {|erro| self.errors.add(:base, erro)}
76
+ rescue Errno::ENOENT => e
77
+ self.errors.add(:base, "Arquivo schema não existe")
78
+ rescue Exception => e
79
+ self.errors.add(:base, e)
80
+ ensure
81
+ self.errors.blank?
82
+ end
83
+
84
+ def assinar(tag_assinar)
85
+ assinador = InovadoraXml::Assinador.new(self.xml_gerado, tag_assinar, self.cert, self.key)
86
+ assinador.assinar_xml
87
+
88
+ assinador.errors.full_messages.each do |error|
89
+ self.errors.add(:base, error)
90
+ end
91
+
92
+ self.xml_gerado = assinador.xml_assinado if assinador.errors.blank?
93
+ ensure
94
+ return self.errors.blank?
95
+ end
96
+ end
6
97
  end
@@ -0,0 +1,122 @@
1
+ #encoding=utf-8
2
+ module InovadoraXml
3
+ class Assinador
4
+ attr_accessor :xml_assinar, :xml_assinado, :tag_assinar, :cert, :key, :errors, :parametro
5
+
6
+ def initialize(xml, tag_assinar, cert, key)
7
+ self.errors = ActiveModel::Errors.new(self)
8
+
9
+ self.xml_assinar = xml.to_s
10
+ self.tag_assinar = tag_assinar
11
+ self.cert = cert
12
+ self.key = key
13
+ end
14
+
15
+ def assinar_xml()
16
+ if self.valid?
17
+ chave_privada = OpenSSL::PKey::RSA.new(File.read(self.key))
18
+ certificado = OpenSSL::X509::Certificate.new(File.read(self.cert))
19
+
20
+ self.xml_assinado = Nokogiri::XML(self.xml_assinar.to_s, &:noblanks)
21
+ self.xml_assinado.xpath("//xmlns:#{self.tag_assinar}").each do |node|
22
+
23
+ # 1. Digest Hash for all XML
24
+ xml_canon = node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
25
+ xml_digest = Base64.encode64(OpenSSL::Digest::SHA1.digest(xml_canon)).strip
26
+
27
+ # 2. Add Signature Node
28
+ signature = Nokogiri::XML::Node.new('Signature', self.xml_assinado)
29
+ signature.default_namespace = 'http://www.w3.org/2000/09/xmldsig#'
30
+ node.after(signature)
31
+
32
+ # 3.1 Create Signature Info
33
+ signature_info = Nokogiri::XML::Node.new('SignedInfo', self.xml_assinado)
34
+
35
+ # 3.2 Add CanonicalizationMethod
36
+ child_node = Nokogiri::XML::Node.new('CanonicalizationMethod', self.xml_assinado)
37
+ child_node['Algorithm'] = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
38
+ signature_info.add_child child_node
39
+
40
+ # 3.3 Add SignatureMethod
41
+ child_node = Nokogiri::XML::Node.new('SignatureMethod', self.xml_assinado)
42
+ child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
43
+ signature_info.add_child child_node
44
+
45
+ # 3.4 Create Reference
46
+ reference = Nokogiri::XML::Node.new('Reference', self.xml_assinado)
47
+ reference['URI'] = "##{node.first.last}"
48
+
49
+ # 3.5 Add Transforms
50
+ transforms = Nokogiri::XML::Node.new('Transforms', self.xml_assinado)
51
+
52
+ child_node = Nokogiri::XML::Node.new('Transform', self.xml_assinado)
53
+ child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
54
+ transforms.add_child child_node
55
+
56
+ child_node = Nokogiri::XML::Node.new('Transform', self.xml_assinado)
57
+ child_node['Algorithm'] = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
58
+ transforms.add_child child_node
59
+
60
+ reference.add_child transforms
61
+
62
+ # 3.6 Add Digest
63
+ child_node = Nokogiri::XML::Node.new('DigestMethod', self.xml_assinado)
64
+ child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#sha1'
65
+ reference.add_child child_node
66
+
67
+ # 3.6 Add DigestValue
68
+ child_node = Nokogiri::XML::Node.new('DigestValue', self.xml_assinado)
69
+ child_node.content = xml_digest
70
+ reference.add_child child_node
71
+
72
+ # 3.7 Add Reference and Signature Info
73
+ signature_info.add_child reference
74
+ signature.add_child signature_info
75
+
76
+ # 4 Sign Signature
77
+ sign_canon = signature_info.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
78
+ signature_hash = chave_privada.sign(OpenSSL::Digest::SHA1.new, sign_canon)
79
+ signature_value = Base64.encode64(signature_hash).gsub("\n", '')
80
+
81
+ # 4.1 Add SignatureValue
82
+ child_node = Nokogiri::XML::Node.new('SignatureValue', self.xml_assinado)
83
+ child_node.content = signature_value
84
+ signature.add_child child_node
85
+
86
+ # 5 Create KeyInfo
87
+ key_info = Nokogiri::XML::Node.new('KeyInfo', self.xml_assinado)
88
+
89
+ # 5.1 Add X509 Data and Certificate
90
+ x509_data = Nokogiri::XML::Node.new('X509Data', self.xml_assinado)
91
+ x509_certificate = Nokogiri::XML::Node.new('X509Certificate', self.xml_assinado)
92
+ x509_certificate.content = certificado.to_s.gsub(/\-\-\-\-\-[A-Z]+ CERTIFICATE\-\-\-\-\-/, "").gsub(/\n/,"")
93
+
94
+ x509_data.add_child x509_certificate
95
+ key_info.add_child x509_data
96
+
97
+ # 5.2 Add KeyInfo
98
+ signature.add_child key_info
99
+ end
100
+
101
+ # Return XML
102
+ self.xml_assinado.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
103
+ end
104
+ rescue Exception => e
105
+ self.errors.add(:base, e.message)
106
+ ensure
107
+ return self.errors.blank?
108
+ end
109
+
110
+ def valid?
111
+ self.errors.add(:base, "Chave não informada" ) unless self.key.present?
112
+ self.errors.add(:base, "Certificado não informado" ) unless self.cert.present?
113
+ self.errors.add(:base, "Arquivo chave não encontrado") unless File.exists?(self.key.to_s)
114
+ self.errors.add(:base, "Arquivo certificado não encontrado") unless File.exists?(self.cert.to_s)
115
+
116
+ rescue Exception => e
117
+ self.errors.add(:base, e.message)
118
+ ensure
119
+ return self.errors.blank?
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,6 @@
1
+ module InovadoraXml
2
+ module CustomExceptions
3
+ # extend ActiveSupport::Autoload
4
+ autoload :ServerError, "inovadora_xml/custom_exceptions/server_error"
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ module InovadoraXml
2
+ module CustomExceptions
3
+ class ServerError < StandardError
4
+ attr_reader :object
5
+
6
+ def initialize(object)
7
+ @object = object
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module InovadoraXml
2
+ module Modules
3
+ # extend ActiveSupport::Autoload
4
+ autoload :FormatadorNfse, "inovadora_xml/modules/formatador_nfse"
5
+ autoload :GeradorXml, "inovadora_xml/modules/gerador_xml"
6
+ autoload :DadosNfseService, "inovadora_xml/modules/dados_nfse_service"
7
+ autoload :XmlRetorno, "inovadora_xml/modules/xml_retorno"
8
+ end
9
+ end
@@ -0,0 +1,143 @@
1
+ # encoding=utf-8
2
+ module InovadoraXml
3
+ module Modules
4
+ module DadosNfseService
5
+ def get_numero_lote_rps
6
+ self.fnnfse.build_fnnfses_sancionada if self.fnnfse.fnnfses_sancionada.blank?
7
+ (self.fnnfse.fnnfses_sancionada.numero_rps = self.fnnfse.class.connection.select_value("SELECT nextval('gestho.prox_nro_rps_nfse')")) if self.fnnfse.fnnfses_sancionada.numero_rps.to_s == ""
8
+
9
+ self.fnnfse.fnnfses_sancionada.numero_lote_rps = self.fnnfse.class.connection.select_value("SELECT nextval('gestho.prox_nro_lote_rps_nfse')")
10
+ self.fnnfse.fnnfses_sancionada.save
11
+ return self.fnnfse.fnnfses_sancionada.numero_lote_rps
12
+ end
13
+
14
+ def get_itens_servicos
15
+ case self.parametro.fornecedor
16
+ when 7..8 # Publica e #NF-em
17
+ get_itens_servicos_publica
18
+ else
19
+ "Não implementado para esse fornecedor"
20
+ end
21
+ end
22
+
23
+ def get_itens_servicos_publica
24
+ itens_da_nota= "{"
25
+ if self.fnnfse.descritivo_servico.to_s == ""
26
+ unless self.fnnfse.fnpacote.nil?
27
+ itens_da_nota += "[" +
28
+ "[Descricao=#{self.fnnfse.try(:fnpacote).try(:descricao)} #{fnnfse.obs_pacote}]" +
29
+ "[Quantidade=1.0]" +
30
+ "[ValorUnitario=#{self.fnnfse.valor_pacote}]" +
31
+ "[Deducoes=0]" +
32
+ "[DescontoCondicionado=0]" +
33
+ "[DescontoIncondicionado=#{self.fnnfse.valor_pacote_desconto.to_f.round(2)}]" +
34
+ "[Aliquota=#{get_aliquota}]" +
35
+ "[itemServico=#{get_item_lista_servico}]" +
36
+ "]"
37
+ end
38
+ self.fnnfse.fnnfseis.each do |fnnfsei|
39
+ qtde = fnnfsei.qtde.to_f.round(2) == 0 ? 1.0 : fnnfsei.qtde.to_f.round(2)
40
+ itens_da_nota += "[" +
41
+ "[Descricao=#{fnnfsei.ftforma.nome}]" +
42
+ "[Quantidade=#{qtde}]" +
43
+ "[ValorUnitario=#{(fnnfsei.valor.to_f / qtde).round(8)}]" +
44
+ "[Deducoes=0]" +
45
+ "[DescontoCondicionado=0]" +
46
+ "[DescontoIncondicionado=#{fnnfsei.desconto.to_s.to_d}]" +
47
+ "[Aliquota=#{get_aliquota}]" +
48
+ "[itemServico=#{get_item_lista_servico}]" +
49
+ "]"
50
+ end
51
+ else
52
+ itens_da_nota += "[" +
53
+ "[Descricao=#{self.fnnfse.descritivo_servico}]" +
54
+ "[Quantidade=1.0]" +
55
+ "[ValorUnitario=#{self.fnnfse.valor_servicos}]" +
56
+ "[Deducoes=0]" +
57
+ "[DescontoCondicionado=0]" +
58
+ "[DescontoIncondicionado=#{self.fnnfse.valor_descontos}]" +
59
+ "[Aliquota=#{get_aliquota}]" +
60
+ "[itemServico=#{get_item_lista_servico}]" +
61
+ "]"
62
+ end
63
+ itens_da_nota += "}"
64
+ end
65
+
66
+ def get_itens_servicos_texto
67
+ itens_da_nota = ""
68
+ if self.fnnfse.descritivo_servico.to_s == ""
69
+ if self.fnnfse.try(:fnpacote).present?
70
+ itens_da_nota += "#{self.fnnfse.try(:fnpacote).try(:descricao)} #{fnnfse.obs_pacote} " +
71
+ "Valor: #{self.fnnfse.valor_pacote} " +
72
+ "Desconto: #{self.fnnfse.valor_pacote_desconto.to_f.round(2)}"
73
+ end
74
+ if self.fnnfse.fnnfseis.size > 1
75
+ self.fnnfse.fnnfseis.each do |fnnfsei|
76
+ qtde = fnnfsei.qtde.to_f.round(2) == 0 ? 1.0 : fnnfsei.qtde.to_f.round(2)
77
+ itens_da_nota += "- #{fnnfsei.ftforma.nome} Qtde: #{qtde} " +
78
+ "Valor: #{((fnnfsei.valor.to_f / qtde).round(8)).round(2)} " +
79
+ (fnnfsei.desconto.to_s.to_d>0 ? "Desconto: #{fnnfsei.desconto.to_s.to_d.round(2)}" : "") +
80
+ " \n"
81
+ end
82
+ else
83
+ fnnfsei = self.fnnfse.fnnfseis.first
84
+ itens_da_nota += "#{fnnfsei.ftforma.nome}" rescue ""
85
+ end
86
+ else
87
+ itens_da_nota += "#{self.fnnfse.descritivo_servico} " +
88
+ "Valor: #{self.fnnfse.valor_servicos.to_d.round(2)} " +
89
+ (self.fnnfse.valor_descontos.to_d>0 ? "Desconto: #{self.fnnfse.valor_descontos.to_d.round(2)}" : "")
90
+ end
91
+ itens_da_nota
92
+ end
93
+
94
+ def get_informacoes_complementares
95
+ mensagem = self.fnnfse.observacao.to_s.strip
96
+ if self.fnnfse.cliente_type == "Paciente"
97
+ intern = self.fnnfse.fnnfses_interns.try(:first).try(:intern)
98
+ unless intern.blank?
99
+ mensagem += " Intern:#{intern.id}-#{intern.paciente.try(:nome).try(:strip)}"
100
+ mensagem += " Conv.:#{self.fnnfse.get_convenio.try(:nome).try(:strip)}"
101
+ mensagem += " CPF:#{intern.paciente.cpf}" if intern.paciente.cpf.to_s.strip != "" && intern.paciente.cpf.to_s.strip != "0"
102
+ mensagem += " Nasc:#{intern.paciente.data_nascimento.to_s_br}"
103
+ end
104
+ end
105
+ mensagem = nil if mensagem.to_s.strip.blank?
106
+ mensagem
107
+ end
108
+
109
+ def get_item_lista_servico
110
+ self.hospital.iss_cd_lei_116 || '4.03'
111
+ end
112
+
113
+ def get_aliquota
114
+ self.fnnfse.percentual_iss || 0.0
115
+ end
116
+
117
+ def get_cnpj_prestador
118
+ self.hospital.cgc.to_s.gsub(/[^0-9]/, "")
119
+ end
120
+
121
+ def get_inscricao_municipal_prestador
122
+ self.hospital.inscricao_municipal.to_s.gsub(/[^0-9]-/, "")
123
+ end
124
+
125
+ def get_codigo_municipio_prest_servico
126
+ self.hospital.cidade_ibge.try(:ibge_com_digito)
127
+ end
128
+
129
+ def persistir_fnnfses_xml(xml, tipo_documento = 17)
130
+ xml_tratado = Nokogiri::XML(CGI.unescapeHTML(xml.to_xml.to_s), &:noblanks)
131
+ xml_tratado = xml_tratado.to_xml(indent: 2).to_s
132
+ if xml_tratado.blank?
133
+ xml_tratado = "xml não recebido da prefeitura"
134
+ end
135
+ # $b = {fnnfse: self.fnnfse, xml_envio: self.xml_gerado().to_s, xml_retorno: xml_tratado, errors: self.errors, tipo_documento: tipo_documento}
136
+
137
+ retorno_service = InovadoraXml::Modules::XmlRetorno.new(fnnfse: self.fnnfse, xml_envio: self.xml_gerado().to_s, xml_retorno: xml_tratado, errors: self.errors, tipo_documento: tipo_documento)
138
+
139
+ retorno_service.save
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,36 @@
1
+ #encoding: utf-8
2
+ module InovadoraXml
3
+ module Modules
4
+ module FormatadorNfse
5
+ def data_formato_br(data)
6
+ # Padrão: 11/11/2011
7
+ data = data.to_time if data.class == String
8
+ data.strftime('%d/%m/%Y') unless data.nil? || data.to_s == ""
9
+ end
10
+
11
+ def data_nfse(data)
12
+ # Padrão: 2010-11-11
13
+ data = data.to_time if data.class == String
14
+ data.strftime('%Y-%m-%d') unless data.nil? || data.to_s == ""
15
+ end
16
+
17
+ def data_hora_nfse(data)
18
+ # Padrão: 2010-09-16T14:50:00
19
+ data = data.to_time if data.class == String
20
+ data.strftime('%Y-%m-%dT%H:%M:%S') unless data.nil?
21
+ end
22
+
23
+ def data_hora_gmt(data)
24
+ # Padrão: 2010-09-16T14:50:00
25
+ data = data.to_time if data.class == String
26
+ data.strftime('%Y-%m-%dT%H:%M:%S%:z') unless data.nil?
27
+ end
28
+
29
+ def hora_nfse(data)
30
+ # Padrão: 11:26:00
31
+ data = data.to_time if data.class == String
32
+ data.strftime('%H:%M:%S') unless data.nil?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ #encoding: utf-8
2
+ module InovadoraXml
3
+ module Modules
4
+ module GeradorXml
5
+
6
+ def elemento(elemento, valor = nil)
7
+ if valor.class == String
8
+ valor.strip!
9
+ valor = I18n.transliterate(valor)
10
+ regex = /[^a-zA-Z0-9,.\-_\/:\[\]\=\$\@\{\}\/\n ]/
11
+ #regex = /[^a-zA-Z0-9,.\-_\/:\[\]\=\$\@\{\}\/ ]/
12
+ valor = valor.gsub(regex, "")
13
+ end
14
+ self.xml_nfse.send(elemento, valor) {
15
+ yield if block_given?
16
+ } unless valor.nil?
17
+ end
18
+
19
+ def grupo(elemento, id = nil)
20
+ if id.present?
21
+ self.xml_nfse.send(elemento, id) {
22
+ yield if block_given?
23
+ }
24
+ else
25
+ self.xml_nfse.send(elemento) {
26
+ yield if block_given?
27
+ }
28
+ end
29
+ end
30
+
31
+ def construir(elemento_raiz)
32
+ builder = Nokogiri::XML::Builder.new() do |xml|
33
+ self.xml_nfse = xml
34
+ elemento(elemento_raiz, get_namespace) {
35
+ yield
36
+ }
37
+ end
38
+ xml_builder = builder.to_xml(indent: 2, encoding: "UTF-8")
39
+ doc = Nokogiri::XML(xml_builder, &:noblanks)
40
+ return doc
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,105 @@
1
+ #encoding=utf-8
2
+ module InovadoraXml
3
+ module Modules
4
+ class XmlRetorno
5
+ extend ActiveModel::Naming # Requer dependencias para uso do ActiveModel::Errors
6
+ attr_accessor :errors, :fnnfse, :fnnfses_xml, :numero_nota, :link_nota, :protocolo_prefeitura,
7
+ :codigo_verificacao_nfse, :datahora_aprovacao,
8
+ :cancelada, :data_hora_cancelamento
9
+
10
+ def initialize args={}
11
+ self.errors = args[:errors] || ActiveModel::Errors.new(self)
12
+ self.fnnfse = args[:fnnfse]
13
+ validar_dados_iniciais(args)
14
+ persistir_fnnfses_xml(args)
15
+ end
16
+
17
+ def validar_dados_iniciais(args)
18
+ if self.fnnfse.nil?
19
+ self.errors.add(:base, "NFSe não encontrada")
20
+ end
21
+ if args.blank? || args[:xml_envio].blank?
22
+ self.errors.add(:base, "XML para envio está em branco")
23
+ end
24
+ if args.blank? || args[:xml_retorno].blank?
25
+ self.errors.add(:base, "XML de retorno está em branco")
26
+ end
27
+ end
28
+
29
+ def valid?
30
+ self.errors.blank?
31
+ end
32
+
33
+ def retornou_dados_nota?
34
+ self.errors.add(:base, "Número da nota não encontrado no XML de retorno da prefeitura") if self.numero_nota.blank?
35
+ # self.errors.add(:base, "Link da nota não encontrado no XML de retorno da prefeitura") if self.link_nota.blank?
36
+ self.errors.add(:base, "Código verificação da nota não encontrado no XML de retorno da prefeitura") if self.codigo_verificacao_nfse.blank?
37
+ self.errors.add(:base, "Data aprovação da nota não encontrado no XML de retorno da prefeitura") if self.datahora_aprovacao.blank?
38
+ self.valid?
39
+ end
40
+
41
+ def save
42
+ if retornou_dados_nota?
43
+ if self.valid?
44
+ self.fnnfse.nao_validar_nota_autenticada = true
45
+ self.fnnfse.fnnfses_sancionada.numero_nota = self.numero_nota
46
+ self.fnnfse.fnnfses_sancionada.link_nota = self.link_nota
47
+ self.fnnfse.fnnfses_sancionada.codigo_verificacao_nfse = self.codigo_verificacao_nfse
48
+ self.fnnfse.fnnfses_sancionada.datahora_aprovacao = self.datahora_aprovacao
49
+ self.fnnfse.fnnfses_sancionada.protocolo_prefeitura = self.protocolo_prefeitura
50
+ self.fnnfse.save
51
+ end
52
+ if self.cancelada && self.data_hora_cancelamento.present?
53
+ self.fnnfse.reload
54
+ fnnfses_sancionada = self.fnnfse.fnnfses_sancionada
55
+ fnnfses_sancionada.cancelada = true
56
+ fnnfses_sancionada.motivo_cancelamento = fnnfses_sancionada.motivo_cancelamento.to_s + " Data/Hora cancelamento: #{self.data_hora_cancelamento.to_s_br}"
57
+ fnnfses_sancionada.save
58
+ end
59
+ end
60
+ end
61
+
62
+ def get_texto_errors
63
+ texto_errors = '<erros>\n'
64
+ texto_errors += "<erro>XML apresentou erros na geração e transmissão para o webservice</erro>\n"
65
+ if self.errors.present?
66
+ self.errors.full_messages.each do |msg|
67
+ texto_errors += "<erro>#{msg}</erro>\n"
68
+ end
69
+ end
70
+ texto_errors += '</erros>\n'
71
+ texto_errors
72
+ end
73
+
74
+ def persistir_fnnfses_xml(args)
75
+ xml_resposta_ws = (args[:xml_retorno] rescue get_texto_errors)
76
+ if xml_resposta_ws.blank?
77
+ xml_resposta_ws = get_texto_errors
78
+ end
79
+ self.fnnfses_xml = FnnfsesXml.create(
80
+ fnnfse_id: self.fnnfse.id,
81
+ tipo_documento: args[:tipo_documento],
82
+ xml_envio: (args[:xml_envio] rescue get_texto_errors),
83
+ xml_resposta: xml_resposta_ws
84
+ )
85
+ if self.fnnfses_xml.try(:get_erros).present?
86
+ self.fnnfses_xml.get_erros.each do |erro|
87
+ self.errors.add(:base, "Erro retornado pela prefeitura: #{erro}")
88
+ end
89
+ end
90
+
91
+ if self.errors.blank?
92
+ self.numero_nota = self.fnnfses_xml.get_numero_nota if (self.fnnfses_xml.get_numero_nota.present?)
93
+ self.link_nota = self.fnnfses_xml.get_link_nota if (self.fnnfses_xml.get_link_nota.present?)
94
+ self.codigo_verificacao_nfse = self.fnnfses_xml.get_codigo_verificacao_nfse if (self.fnnfses_xml.get_codigo_verificacao_nfse.present?)
95
+ self.datahora_aprovacao = self.fnnfses_xml.get_data_emissao if (self.fnnfses_xml.get_data_emissao.present?)
96
+ self.protocolo_prefeitura = self.fnnfses_xml.get_protocolo_prefeitura if (self.fnnfses_xml.get_protocolo_prefeitura.present?)
97
+ if (self.fnnfses_xml.get_data_hora_cancelamento.present? rescue false)
98
+ self.cancelada = true
99
+ self.data_hora_cancelamento = self.fnnfses_xml.get_data_hora_cancelamento
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,47 @@
1
+ #encoding: utf-8
2
+ module InovadoraXml
3
+ class ServidorWsdl
4
+ attr_accessor :xml_enviar, :metodo_soap, :wsdl, :args_request, :cert, :key, :retorno, :errors
5
+
6
+ def initialize(xml_enviar, metodo_soap, wsdl, cert = nil, key = nil, args_request = {})
7
+ self.xml_enviar = xml_enviar
8
+ self.metodo_soap = metodo_soap
9
+ self.wsdl = wsdl
10
+
11
+ self.cert = cert
12
+ self.key = key
13
+
14
+ self.args_request = args_request
15
+
16
+ self.errors = ActiveModel::Errors.new(self)
17
+ end
18
+
19
+ def enviar
20
+ begin
21
+ cliente = estabelecer_cliente()
22
+
23
+ response = cliente.request(self.metodo_soap, args_request) do
24
+ soap.xml = self.xml_enviar
25
+ end
26
+ self.retorno = response
27
+ rescue Savon::SOAP::Fault => fault
28
+ self.errors.add(:base, fault.to_s)
29
+ rescue Savon::HTTP::Error => fault2
30
+ self.errors.add(:base, fault2.to_s)
31
+ rescue Exception => e
32
+ self.errors.add(:base, e.message)
33
+ ensure
34
+ return self.errors.blank?
35
+ end
36
+ end
37
+
38
+ def estabelecer_cliente
39
+ Savon::Client.new do |wsdl, http|
40
+ wsdl.document = self.wsdl
41
+ http.auth.ssl.cert_file = self.cert unless self.cert.blank?
42
+ http.auth.ssl.cert_key_file = self.key unless self.key.blank?
43
+ http.auth.ssl.verify_mode = :none
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module InovadoraXml
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.6"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inovadora_xml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2019-06-07 00:00:00.000000000 Z
12
+ date: 2020-06-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -44,13 +44,13 @@ dependencies:
44
44
  - !ruby/object:Gem::Version
45
45
  version: '10.0'
46
46
  - !ruby/object:Gem::Dependency
47
- name: nokogiri
47
+ name: signer
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  none: false
50
50
  requirements:
51
51
  - - '='
52
52
  - !ruby/object:Gem::Version
53
- version: 1.6.0
53
+ version: 1.4.2
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,23 +58,23 @@ dependencies:
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 1.6.0
61
+ version: 1.4.2
62
62
  - !ruby/object:Gem::Dependency
63
- name: signer
63
+ name: nokogiri
64
64
  requirement: !ruby/object:Gem::Requirement
65
65
  none: false
66
66
  requirements:
67
- - - '='
67
+ - - ! '>='
68
68
  - !ruby/object:Gem::Version
69
- version: 1.4.2
70
- type: :development
69
+ version: 1.4.0
70
+ type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
- - - '='
75
+ - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
- version: 1.4.2
77
+ version: 1.4.0
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: savon
80
80
  requirement: !ruby/object:Gem::Requirement
@@ -83,7 +83,7 @@ dependencies:
83
83
  - - '='
84
84
  - !ruby/object:Gem::Version
85
85
  version: 1.2.0
86
- type: :development
86
+ type: :runtime
87
87
  prerelease: false
88
88
  version_requirements: !ruby/object:Gem::Requirement
89
89
  none: false
@@ -91,6 +91,22 @@ dependencies:
91
91
  - - '='
92
92
  - !ruby/object:Gem::Version
93
93
  version: 1.2.0
94
+ - !ruby/object:Gem::Dependency
95
+ name: wasabi
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - '='
100
+ - !ruby/object:Gem::Version
101
+ version: 2.5.0
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - '='
108
+ - !ruby/object:Gem::Version
109
+ version: 2.5.0
94
110
  description:
95
111
  email:
96
112
  - evanor.libardoni@gmail.com
@@ -106,8 +122,18 @@ files:
106
122
  - Rakefile
107
123
  - bin/console
108
124
  - bin/setup
125
+ - inovadora_xml-0.0.2.gem
109
126
  - inovadora_xml.gemspec
110
127
  - lib/inovadora_xml.rb
128
+ - lib/inovadora_xml/assinador.rb
129
+ - lib/inovadora_xml/custom_exceptions.rb
130
+ - lib/inovadora_xml/custom_exceptions/server_error.rb
131
+ - lib/inovadora_xml/modules.rb
132
+ - lib/inovadora_xml/modules/dados_nfse_service.rb
133
+ - lib/inovadora_xml/modules/formatador_nfse.rb
134
+ - lib/inovadora_xml/modules/gerador_xml.rb
135
+ - lib/inovadora_xml/modules/xml_retorno.rb
136
+ - lib/inovadora_xml/servidor_wsdl.rb
111
137
  - lib/inovadora_xml/version.rb
112
138
  homepage:
113
139
  licenses: