inovadora_xml 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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) }
@@ -0,0 +1,102 @@
1
+ #encoding=utf-8
2
+ module InovadoraXml
3
+ class Assinador
4
+ attr_accessor :xml_assinar, :xml_assinado, :tag_assinar, :parametro
5
+
6
+ def initialize(xml, tag_assinar)
7
+ self.xml_assinar = xml.to_s
8
+ self.tag_assinar = tag_assinar
9
+ self.assinar_xml
10
+ end
11
+
12
+ def assinar_xml()
13
+ chave_privada = OpenSSL::PKey::RSA.new(File.read("#{Rails.root}/app/services/sefaz/assinatura/chave.cer"))
14
+ certificado = OpenSSL::X509::Certificate.new(File.read("#{Rails.root}/app/services/sefaz/assinatura/certificado.cer"))
15
+
16
+ self.xml_assinado = Nokogiri::XML(self.xml_assinar.to_s, &:noblanks)
17
+ self.xml_assinado.xpath("//xmlns:#{self.tag_assinar}").each do |node|
18
+
19
+ # 1. Digest Hash for all XML
20
+ xml_canon = node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
21
+ xml_digest = Base64.encode64(OpenSSL::Digest::SHA1.digest(xml_canon)).strip
22
+
23
+ # 2. Add Signature Node
24
+ signature = Nokogiri::XML::Node.new('Signature', self.xml_assinado)
25
+ signature.default_namespace = 'http://www.w3.org/2000/09/xmldsig#'
26
+ node.after(signature)
27
+
28
+ # 3.1 Create Signature Info
29
+ signature_info = Nokogiri::XML::Node.new('SignedInfo', self.xml_assinado)
30
+
31
+ # 3.2 Add CanonicalizationMethod
32
+ child_node = Nokogiri::XML::Node.new('CanonicalizationMethod', self.xml_assinado)
33
+ child_node['Algorithm'] = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
34
+ signature_info.add_child child_node
35
+
36
+ # 3.3 Add SignatureMethod
37
+ child_node = Nokogiri::XML::Node.new('SignatureMethod', self.xml_assinado)
38
+ child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
39
+ signature_info.add_child child_node
40
+
41
+ # 3.4 Create Reference
42
+ reference = Nokogiri::XML::Node.new('Reference', self.xml_assinado)
43
+ reference['URI'] = "##{node.first.last}"
44
+
45
+ # 3.5 Add Transforms
46
+ transforms = Nokogiri::XML::Node.new('Transforms', self.xml_assinado)
47
+
48
+ child_node = Nokogiri::XML::Node.new('Transform', self.xml_assinado)
49
+ child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
50
+ transforms.add_child child_node
51
+
52
+ child_node = Nokogiri::XML::Node.new('Transform', self.xml_assinado)
53
+ child_node['Algorithm'] = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
54
+ transforms.add_child child_node
55
+
56
+ reference.add_child transforms
57
+
58
+ # 3.6 Add Digest
59
+ child_node = Nokogiri::XML::Node.new('DigestMethod', self.xml_assinado)
60
+ child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#sha1'
61
+ reference.add_child child_node
62
+
63
+ # 3.6 Add DigestValue
64
+ child_node = Nokogiri::XML::Node.new('DigestValue', self.xml_assinado)
65
+ child_node.content = xml_digest
66
+ reference.add_child child_node
67
+
68
+ # 3.7 Add Reference and Signature Info
69
+ signature_info.add_child reference
70
+ signature.add_child signature_info
71
+
72
+ # 4 Sign Signature
73
+ sign_canon = signature_info.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
74
+ signature_hash = chave_privada.sign(OpenSSL::Digest::SHA1.new, sign_canon)
75
+ signature_value = Base64.encode64( signature_hash ).gsub("\n", '')
76
+
77
+ # 4.1 Add SignatureValue
78
+ child_node = Nokogiri::XML::Node.new('SignatureValue', self.xml_assinado)
79
+ child_node.content = signature_value
80
+ signature.add_child child_node
81
+
82
+ # 5 Create KeyInfo
83
+ key_info = Nokogiri::XML::Node.new('KeyInfo', self.xml_assinado)
84
+
85
+ # 5.1 Add X509 Data and Certificate
86
+ x509_data = Nokogiri::XML::Node.new('X509Data', self.xml_assinado)
87
+ x509_certificate = Nokogiri::XML::Node.new('X509Certificate', self.xml_assinado)
88
+ x509_certificate.content = certificado.to_s.gsub(/\-\-\-\-\-[A-Z]+ CERTIFICATE\-\-\-\-\-/, "").gsub(/\n/,"")
89
+
90
+ x509_data.add_child x509_certificate
91
+ key_info.add_child x509_data
92
+
93
+ # 5.2 Add KeyInfo
94
+ signature.add_child key_info
95
+ end
96
+
97
+ # Return XML
98
+ self.xml_assinado.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,7 @@
1
+ class Utils::Xml::CustomExceptions::ServerError < StandardError
2
+ attr_reader :object
3
+
4
+ def initialize(object)
5
+ @object = object
6
+ end
7
+ end
@@ -0,0 +1,130 @@
1
+ # encoding=utf-8
2
+ module InovadoraXml
3
+ module Modules
4
+ module DadosNfseService
5
+ def numero_lote_rps
6
+ self.fnnfse.build_fnnfses_sancionada if self.fnnfse.fnnfses_sancionada.blank?
7
+ if self.fnnfse.fnnfses_sancionada.numero_rps.to_s == ""
8
+ self.fnnfse.fnnfses_sancionada.numero_rps = self.fnnfse.class.connection.select_value("SELECT nextval('gestho.prox_nro_rps_nfse')")
9
+ self.fnnfse.fnnfses_sancionada.save
10
+ end
11
+ return self.fnnfse.fnnfses_sancionada.numero_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.:#{intern.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
+ end
129
+ end
130
+ 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,8 @@
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
+ end
8
+ end
@@ -0,0 +1,54 @@
1
+ #encoding: utf-8
2
+ module InovadoraXml
3
+ class ServidorWsdl
4
+ attr_accessor :xml_enviar, :metodo_soap, :wsdl, :args_request, :certificado, :chave, :retorno, :errors
5
+
6
+
7
+ # servidor = Utils::Xml::ServidorWsdl.new(
8
+ # gerar_xml_enviar,
9
+ # self.metodo_soap,
10
+ # "https://hom.nfe.fazenda.gov.br/NFeDistribuicaoDFe/NFeDistribuicaoDFe.asmx?WSDL",
11
+ # {soap_action: "http://www.portalfiscal.inf.br/nfe/wsdl/NFeDistribuicaoDFe/nfeDistDFeInteresse"}
12
+ # )
13
+ def initialize(xml_enviar, metodo_soap, wsdl, args_request = {})
14
+ self.xml_enviar = xml_enviar
15
+ self.metodo_soap = metodo_soap
16
+ self.wsdl = wsdl
17
+
18
+ self.certificado = "#{Rails.root}/app/services/sefaz/assinatura/certificado.cer"
19
+ self.chave = "#{Rails.root}/app/services/sefaz/assinatura/chave.cer"
20
+
21
+ self.args_request = args_request
22
+
23
+ self.errors = ActiveModel::Errors.new(self)
24
+ end
25
+
26
+ def enviar
27
+ begin
28
+ cliente = estabelecer_cliente()
29
+
30
+ response = cliente.request(self.metodo_soap, args_request) do
31
+ soap.xml = self.xml_enviar
32
+ end
33
+ self.retorno = response
34
+ rescue Savon::SOAP::Fault => fault
35
+ self.errors.add(:base, fault.to_s)
36
+ rescue Savon::HTTP::Error => fault2
37
+ self.errors.add(:base, fault2.to_s)
38
+ rescue Exception => e
39
+ self.errors.add(:base, e.message)
40
+ ensure
41
+ return self.errors.blank?
42
+ end
43
+ end
44
+
45
+ def estabelecer_cliente
46
+ Savon::Client.new do |wsdl, http|
47
+ wsdl.document = self.wsdl
48
+ http.auth.ssl.cert_file = self.certificado unless self.certificado.blank?
49
+ http.auth.ssl.cert_key_file = self.chave unless self.certificado.blank?
50
+ http.auth.ssl.verify_mode = :none
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,3 +1,3 @@
1
1
  module InovadoraXml
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/inovadora_xml.rb CHANGED
@@ -1,6 +1,88 @@
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
+
15
+ class Xml
16
+ attr_accessor :xml_nfse, :schema, :metodo_soap, :xml_gerado, :retorno, :wsdl, :cert, :key, :errors
17
+
18
+ include InovadoraXml::Modules::FormatadorNfse
19
+ include InovadoraXml::Modules::GeradorXml
20
+
21
+ def initialize(args = {})
22
+ self.errors = ActiveModel::Errors.new(self)
23
+ self.xml_gerado = self.gerar_xml()
24
+
25
+ self.validar_args
26
+ # self.valid?
27
+ end
28
+
29
+ def comunicar(request_args = {})
30
+ self.valid?
31
+
32
+ if self.errors.blank?
33
+ servidor = Utils::Xml::ServidorWsdl.new(
34
+ envelopar(),
35
+ self.metodo_soap,
36
+ self.wsdl,
37
+ request_args
38
+ )
39
+
40
+ unless servidor.enviar
41
+ raise Utils::Xml::CustomExceptions::ServerError.new(servidor), "Server Error"
42
+ end
43
+ #usage: self.retorno.to_xml ou self.retorno.body
44
+ self.retorno = servidor.retorno
45
+ end
46
+
47
+ rescue Utils::Xml::CustomExceptions::ServerError => e
48
+ e.object.errors.full_messages.each {|e| self.errors.add(:base, e)}
49
+ rescue Exception => e
50
+ self.errors.add(:base, e.message)
51
+ ensure
52
+ return self.errors.blank?
53
+ end
54
+
55
+ def validar_args
56
+ self.errors.add(:base, "Metodo SOAP não especificado") if self.metodo_soap.blank?
57
+ self.errors.add(:base, "Schema não especificado") if self.schema.blank?
58
+ self.errors.add(:base, "WSDL não especificado") if self.wsdl.blank?
59
+
60
+ return self.errors.blank?
61
+ end
62
+
63
+ def valid?
64
+ erros = []
65
+ schema = open(self.schema)
66
+ xsd = Nokogiri::XML::Schema(schema)
67
+ xsd.validate(self.xml_gerado).each do |error|
68
+ unless error.message.to_s.include?("{http://www.w3.org/2000/09/xmldsig#}Signature") ||
69
+ error.message.to_s.include?("{http://www.w3.org/2000/09/xmldsig#}SignedInfo")
70
+ erros << "(Linha: " + error.line.to_s + ") => " + error.message.to_s
71
+ end
72
+ end
73
+
74
+ erros.each {|erro| self.errors.add(:base, erro)}
75
+ rescue Errno::ENOENT => e
76
+ self.errors.add(:base, "Arquivo schema não existe")
77
+ rescue Exception => e
78
+ self.errors.add(:base, e)
79
+ ensure
80
+ self.errors.blank?
81
+ end
82
+
83
+ def assinar(xml_assinar, tag_assinar)
84
+ Assinador.new(xml_assinar, tag_assinar).xml_assinado
85
+ end
86
+
87
+ end
6
88
  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.2
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: 2019-06-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -108,6 +108,13 @@ files:
108
108
  - bin/setup
109
109
  - inovadora_xml.gemspec
110
110
  - lib/inovadora_xml.rb
111
+ - lib/inovadora_xml/assinador.rb
112
+ - lib/inovadora_xml/custom_exceptions/server_error.rb
113
+ - lib/inovadora_xml/modules.rb
114
+ - lib/inovadora_xml/modules/dados_nfse_service.rb
115
+ - lib/inovadora_xml/modules/formatador_nfse.rb
116
+ - lib/inovadora_xml/modules/gerador_xml.rb
117
+ - lib/inovadora_xml/servidor_wsdl.rb
111
118
  - lib/inovadora_xml/version.rb
112
119
  homepage:
113
120
  licenses: