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
data/lib/sefaz/base.rb ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ # Classe genérica para todas outras classes base da biblioteca
5
+ class Base
6
+
7
+ def initialize
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ # Classe base para parametrização da biblioteca
5
+ class Configuration
6
+
7
+ # Configuração da formatação de valores monetários
8
+ attr_accessor :currency_format
9
+
10
+ # CF-e (Cupom Fiscal Eletrônico)
11
+ attr_accessor :cfe_qr_code_aplicativo
12
+ attr_accessor :cfe_cMP_cod_desc
13
+
14
+ # 55mm
15
+ attr_accessor :cfe_page_width_55mm
16
+ attr_accessor :cfe_margin_55mm
17
+
18
+ # 80mm
19
+ attr_accessor :cfe_page_width_80mm
20
+ attr_accessor :cfe_margin_80mm
21
+
22
+ def initialize
23
+ @currency_format = { delimiter: ".", separator: ",", unit: "", precision: 2, position: "before" }
24
+ @cfe_qr_code_aplicativo = "De olho na nota"
25
+ @cfe_cMP_cod_desc = {
26
+ "01" => "Dinheiro",
27
+ "02" => "Cheque",
28
+ "03" => "Cartão de Crédito",
29
+ "04" => "Cartão de Débito",
30
+ "05" => "Crédito Loja",
31
+ "10" => "Vale Alimentação",
32
+ "11" => "Vale Refeição",
33
+ "12" => "Vale Presente",
34
+ "13" => "Vale Combustível",
35
+ "15" => "Boleto Bancário",
36
+ "16" => "Depósito Bancário",
37
+ "17" => "Pagamento Instantâneo (PIX)",
38
+ "18" => "Transferência bancária, Carteira Digital",
39
+ "19" => "Programa de fidelidade, Cashback, Crédito Virtual",
40
+ "90" => "Sem pagamento",
41
+ "99" => "Outros"
42
+ }
43
+
44
+ # 50mm
45
+ @cfe_page_width_55mm = 55.mm
46
+ @cfe_margin_55mm = 5.mm
47
+
48
+ # 80mm
49
+ @cfe_page_width_80mm = 80.mm
50
+ @cfe_margin_80mm = 5.mm
51
+ end
52
+
53
+ def self.default
54
+ @default ||= Configuration.new
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+
5
+ class Error < StandardError
6
+ end
7
+
8
+ class ValidationError < StandardError
9
+ end
10
+
11
+ class NotImplemented < RuntimeError
12
+ end
13
+
14
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ # Módulo base de refinamento da biblioteca
5
+ module Refinement
6
+
7
+ module String
8
+ def to_hash!
9
+ Nori.new(convert_tags_to: lambda { |key| key.to_sym }).parse(self)
10
+ end
11
+
12
+ def compress!
13
+ doc = Nokogiri::XML::Document.parse(self, nil, "utf-8", Nokogiri::XML::ParseOptions::NOBLANKS)
14
+ doc.search('*').each { |node| node.remove if node.content.strip.blank? }
15
+ doc.canonicalize
16
+ end
17
+
18
+ def mask!(mask)
19
+ index = -1
20
+ mask.gsub('#') { self[index += 1] }
21
+ end
22
+
23
+ def to_number(options={})
24
+ return self.gsub(/,/, '.').to_f if self.numeric?
25
+ nil
26
+ end
27
+
28
+ def numeric?
29
+ self =~ /^(|-)?[0-9]+((\.|,)[0-9]+)?$/ ? true : false
30
+ end
31
+
32
+ def to_currency(options = {})
33
+ return self.to_number.to_currency(options) if self.numeric?
34
+ nil
35
+ end
36
+ end
37
+
38
+ module Hash
39
+ def to_xml!
40
+ Gyoku.xml(self, key_converter: :none)
41
+ end
42
+
43
+ def compress!
44
+ self.to_xml!.compress!.to_hash!
45
+ end
46
+ end
47
+
48
+ module Currency
49
+ def to_currency(options = {})
50
+ number = self
51
+ default = Configuration.default.currency_format
52
+ options = default.merge(options)
53
+ precision = options[:precision] || default[:precision]
54
+ unit = options[:unit] || default[:unit]
55
+ position = options[:position] || default[:position]
56
+ separator = precision > 0 ? options[:separator] || default[:separator] : ""
57
+ delimiter = options[:delimiter] || default[:delimiter]
58
+
59
+ begin
60
+ parts = number.with_precision(precision).split('.')
61
+ number = parts[0].to_i.with_delimiter(delimiter) + separator + parts[1].to_s
62
+ position == "before" ? unit + number : number + unit
63
+ rescue
64
+ number
65
+ end
66
+ end
67
+
68
+ def with_delimiter(delimiter = ",", separator = ".")
69
+ number = self
70
+ begin
71
+ parts = number.to_s.split(separator)
72
+ parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
73
+ parts.join separator
74
+ rescue
75
+ self
76
+ end
77
+ end
78
+
79
+ def with_precision(precision = 3)
80
+ number = self
81
+ "%01.#{precision}f" % number
82
+ end
83
+ end
84
+
85
+ end
86
+ end
87
+
88
+ String.class_eval { include SEFAZ::Refinement::String }
89
+ Hash.class_eval { include SEFAZ::Refinement::Hash }
90
+ Integer.class_eval { include SEFAZ::Refinement::Currency }
91
+ Float.class_eval { include SEFAZ::Refinement::Currency }
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Utils
5
+ # Classe base de conexão SOAP da biblioteca
6
+ class Connection
7
+
8
+ def initialize(pkcs12, wsdl, soap_header)
9
+ @conn = Savon.client(
10
+ wsdl: wsdl,
11
+ ssl_verify_mode: :none,
12
+ ssl_cert: pkcs12.certificate,
13
+ ssl_cert_key: pkcs12.key,
14
+ soap_header: soap_header,
15
+ soap_version: 2,
16
+ convert_request_keys_to: :none,
17
+ convert_response_tags_to: lambda { |key| key.to_sym },
18
+ namespace_identifier: nil
19
+ )
20
+ end
21
+
22
+ def connected?; (@conn.operations.length > 0) end
23
+ def operations; (@conn.operations) end
24
+
25
+ def build(operation, hash)
26
+ @conn.build_request(operation, message: hash)
27
+ end
28
+
29
+ def call(operation, hash)
30
+ @conn.call(operation, message: hash)
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Utils
5
+ # Módulo com recursos adicionais para os templates baseados na Prawn
6
+ module PrawnHelper
7
+
8
+ def dash(doc, gap:, space:, line_width:, x1:, x2:, y:)
9
+ doc.dash(gap, space: space)
10
+ doc.line_width line_width
11
+ doc.stroke_horizontal_line x1, x2, at: y
12
+ doc.move_down 2
13
+ end
14
+
15
+ def barcode_128c(doc, value:, x:, y:, xdim: 1, height: 20, margin: 0, unbleed: 0, color: '000000')
16
+ barcode = Barby::Code128C.new(value)
17
+ outputter = Barby::PrawnOutputter.new(barcode)
18
+ outputter.x = x
19
+ outputter.y = (y - height)
20
+ outputter.xdim = xdim
21
+ outputter.height = height
22
+ outputter.margin = margin
23
+ outputter.unbleed = unbleed
24
+ outputter.color = color
25
+
26
+ doc.move_down height
27
+ outputter.annotate_pdf doc
28
+ end
29
+
30
+ def qrcode(doc, value:, x:, y:, xdim: 1, margin: 0, unbleed: 0, color: '000000')
31
+ qrcode = Barby::QrCode.new(value)
32
+ outputter = Barby::PrawnOutputter.new(qrcode)
33
+ height = (outputter.boolean_groups.length * xdim)
34
+ outputter.x = x
35
+ outputter.y = (y - height)
36
+ outputter.xdim = xdim
37
+ outputter.margin = margin
38
+ outputter.unbleed = unbleed
39
+ outputter.color = color
40
+
41
+ doc.move_down height
42
+ outputter.annotate_pdf doc
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Utils
5
+ # Classe base de assinatura de XML da biblioteca
6
+ class Signer
7
+
8
+ def initialize(xml)
9
+ @doc = Nokogiri::XML::Document.parse(xml, nil, "utf-8", Nokogiri::XML::ParseOptions::NOBLANKS)
10
+ end
11
+
12
+ def sign!(cert, key)
13
+ @cert = cert
14
+ @key = key
15
+ @doc.root.add_child(signature)
16
+ end
17
+
18
+ def to_xml
19
+ return @doc.canonicalize
20
+ end
21
+
22
+ private
23
+
24
+ def signature
25
+ # Create Signature
26
+ node = Nokogiri::XML::Node.new('Signature', @doc)
27
+ node.default_namespace = 'http://www.w3.org/2000/09/xmldsig#'
28
+ node.add_child signature_info
29
+ node.add_child signature_value
30
+ node.add_child key_info
31
+ node
32
+ end
33
+
34
+ def signature_info
35
+ # Create SignatureInfo
36
+ node = Nokogiri::XML::Node.new('SignedInfo', @doc)
37
+
38
+ # Add CanonicalizationMethod
39
+ child_node = Nokogiri::XML::Node.new('CanonicalizationMethod', @doc)
40
+ child_node['Algorithm'] = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
41
+ node.add_child child_node
42
+
43
+ # Add SignatureMethod
44
+ child_node = Nokogiri::XML::Node.new('SignatureMethod', @doc)
45
+ child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
46
+ node.add_child child_node
47
+
48
+ # Add Reference
49
+ node.add_child reference
50
+ node
51
+ end
52
+
53
+ def signature_value
54
+ # Sign Signature
55
+ xml = Nokogiri::XML(signature_info.to_xml, &:noblanks)
56
+ xml.root["xmlns"] = 'http://www.w3.org/2000/09/xmldsig#'
57
+ sign_canon = xml.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
58
+ signature_hash = @key.sign(OpenSSL::Digest::SHA1.new, sign_canon)
59
+
60
+ # Add SignatureValue
61
+ node = Nokogiri::XML::Node.new('SignatureValue', @doc)
62
+ node.content = Base64.encode64(signature_hash).gsub("\n", '')
63
+ node
64
+ end
65
+
66
+ def key_info
67
+ # Create KeyInfo
68
+ node = Nokogiri::XML::Node.new('KeyInfo', @doc)
69
+
70
+ # Add X509 Data and Certificate
71
+ x509_data = Nokogiri::XML::Node.new('X509Data', @doc)
72
+ x509_certificate = Nokogiri::XML::Node.new('X509Certificate', @doc)
73
+ x509_certificate.content = @cert.to_pem.gsub(/\-\-\-\-\-[A-Z]+ CERTIFICATE\-\-\-\-\-/, "").gsub(/\n/,"")
74
+
75
+ x509_data.add_child x509_certificate
76
+ node.add_child x509_data
77
+ node
78
+ end
79
+
80
+ def reference
81
+ inf = @doc.at_xpath("//*[@Id]")
82
+
83
+ # Calculate digest
84
+ xml_canon = inf.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
85
+ xml_digest = Base64.encode64(OpenSSL::Digest::SHA1.digest(xml_canon)).strip
86
+
87
+ # Create Reference
88
+ node = Nokogiri::XML::Node.new('Reference', @doc)
89
+ node['URI'] = "##{inf['Id']}"
90
+ node.add_child transforms
91
+
92
+ # Add Digest
93
+ child_node = Nokogiri::XML::Node.new('DigestMethod', @doc)
94
+ child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#sha1'
95
+ node.add_child child_node
96
+
97
+ # Add DigestValue
98
+ child_node = Nokogiri::XML::Node.new('DigestValue', @doc)
99
+ child_node.content = xml_digest
100
+ node.add_child child_node
101
+ node
102
+ end
103
+
104
+ def transforms
105
+ # Add Transforms
106
+ node = Nokogiri::XML::Node.new('Transforms', @doc)
107
+
108
+ # Add Transform
109
+ child_node = Nokogiri::XML::Node.new('Transform', @doc)
110
+ child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
111
+ node.add_child child_node
112
+
113
+ # Add Transform
114
+ child_node = Nokogiri::XML::Node.new('Transform', @doc)
115
+ child_node['Algorithm'] = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
116
+ node.add_child child_node
117
+ node
118
+ end
119
+
120
+ end
121
+ end
122
+ end
data/lib/sefaz/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SEFAZ
4
- VERSION = "0.2.0"
4
+ VERSION = "1.3.0"
5
5
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Webservice
5
+ # Classe base para todas as integrações - Webservice
6
+ class Base < SEFAZ::Base
7
+
8
+ def initialize
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SEFAZ
4
+ module Webservice
5
+ module NFE
6
+ # Auditor de XML pelo validador público da Tecnospeed
7
+ class Auditor
8
+
9
+ def initialize(xml)
10
+ @xml = xml
11
+ end
12
+
13
+ def exec(openTimeout, readTimeout)
14
+ uri = URI("https://validadornfe.tecnospeed.com.br/validar")
15
+ http = Net::HTTP.new(uri.host, uri.port)
16
+ http.use_ssl = true
17
+ http.open_timeout = openTimeout
18
+ http.read_timeout = readTimeout
19
+ content = Net::HTTP::Post.new(uri.request_uri)
20
+ content.set_form_data(txtXML: @xml)
21
+ response = http.request(content)
22
+ if response.code == "200"
23
+ url = JSON(response.body)["url"]
24
+ url_esc = url.to_s.sub("{", "%7B").sub("}", "%7D")
25
+ txt_uri = URI(url_esc)
26
+ body = CGI.unescape(Net::HTTP.get(txt_uri))
27
+ return [:ok, JSON(body)]
28
+ end
29
+ return [:error, {}]
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+ end