nfse_sjc 0.1.1

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +4 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +22 -0
  8. data/README.md +130 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +7 -0
  11. data/bin/setup +7 -0
  12. data/etc/codegen/_signature.xml.erb +22 -0
  13. data/etc/codegen/cabecalho_v3.xml.erb +6 -0
  14. data/etc/codegen/cancelar_nfse_v3.xml.erb +21 -0
  15. data/etc/codegen/consultar_lote_rps_v3.xml.erb +15 -0
  16. data/etc/codegen/consultar_nfse_rps_v3.xml.erb +18 -0
  17. data/etc/codegen/consultar_nfse_v3.xml.erb +58 -0
  18. data/etc/codegen/consultar_situacao_lote_rps_v3.xml.erb +15 -0
  19. data/etc/codegen/recepcionar_lote_rps_v3.xml.erb +188 -0
  20. data/etc/schemas/cabecalho_v03.xsd +16 -0
  21. data/etc/schemas/servico_cancelar_nfse_envio_v03.xsd +19 -0
  22. data/etc/schemas/servico_cancelar_nfse_resposta_v03.xsd +13 -0
  23. data/etc/schemas/servico_consultar_lote_rps_envio_v03.xsd +23 -0
  24. data/etc/schemas/servico_consultar_lote_rps_resposta_v03.xsd +18 -0
  25. data/etc/schemas/servico_consultar_nfse_envio_v03.xsd +26 -0
  26. data/etc/schemas/servico_consultar_nfse_resposta_v03.xsd +19 -0
  27. data/etc/schemas/servico_consultar_nfse_rps_envio_v03.xsd +23 -0
  28. data/etc/schemas/servico_consultar_nfse_rps_resposta_v03.xsd +13 -0
  29. data/etc/schemas/servico_consultar_situacao_lote_rps_envio_v03.xsd +17 -0
  30. data/etc/schemas/servico_consultar_situacao_lote_rps_resposta_v03.xsd +16 -0
  31. data/etc/schemas/servico_enviar_lote_rps_envio_v03.xsd +14 -0
  32. data/etc/schemas/servico_enviar_lote_rps_resposta_v03.xsd +25 -0
  33. data/etc/schemas/tipos_v03.xsd +545 -0
  34. data/etc/schemas/xmldsig-core-schema20020212_v03.xsd +316 -0
  35. data/lib/nfse_sjc.rb +22 -0
  36. data/lib/nfse_sjc/client.rb +49 -0
  37. data/lib/nfse_sjc/config.rb +31 -0
  38. data/lib/nfse_sjc/dirs.rb +23 -0
  39. data/lib/nfse_sjc/document.rb +67 -0
  40. data/lib/nfse_sjc/errors/validation_error.rb +6 -0
  41. data/lib/nfse_sjc/parser.rb +15 -0
  42. data/lib/nfse_sjc/response_hash.rb +24 -0
  43. data/lib/nfse_sjc/schemas.rb +17 -0
  44. data/lib/nfse_sjc/version.rb +3 -0
  45. data/nfse_sjc.gemspec +32 -0
  46. metadata +175 -0
@@ -0,0 +1,316 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Schema for XML Signatures
3
+ http://www.w3.org/2000/09/xmldsig#
4
+ $Revision: 1.7 $ on $Date: 2007/09/20 19:06:50 $ by $Author: p052373 $
5
+
6
+ Copyright 2001 The Internet Society and W3C (Massachusetts Institute
7
+ of Technology, Institut National de Recherche en Informatique et en
8
+ Automatique, Keio University). All Rights Reserved.
9
+ http://www.w3.org/Consortium/Legal/
10
+
11
+ This document is governed by the W3C Software License [1] as described
12
+ in the FAQ [2].
13
+
14
+ [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
15
+ [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
16
+ -->
17
+
18
+ <!--
19
+
20
+ Download em 23/02/2007
21
+ Link:
22
+ http://www.w3.org/TR/xmldsig-core/#sec-Schema
23
+ http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema_v03.xsd
24
+
25
+ -->
26
+
27
+ <schema xmlns="http://www.w3.org/2001/XMLSchema"
28
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
29
+ targetNamespace="http://www.w3.org/2000/09/xmldsig#"
30
+ version="0.1" elementFormDefault="qualified">
31
+
32
+ <!-- Basic Types Defined for Signatures -->
33
+
34
+ <simpleType name="CryptoBinary">
35
+ <restriction base="base64Binary">
36
+ </restriction>
37
+ </simpleType>
38
+
39
+ <!-- Start Signature -->
40
+
41
+ <element name="Signature" type="ds:SignatureType"/>
42
+ <complexType name="SignatureType">
43
+ <sequence>
44
+ <element ref="ds:SignedInfo"/>
45
+ <element ref="ds:SignatureValue"/>
46
+ <element ref="ds:KeyInfo" minOccurs="0"/>
47
+ <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/>
48
+ </sequence>
49
+ <attribute name="Id" type="ID" use="optional"/>
50
+ </complexType>
51
+
52
+ <element name="SignatureValue" type="ds:SignatureValueType"/>
53
+ <complexType name="SignatureValueType">
54
+ <simpleContent>
55
+ <extension base="base64Binary">
56
+ <attribute name="Id" type="ID" use="optional"/>
57
+ </extension>
58
+ </simpleContent>
59
+ </complexType>
60
+
61
+ <!-- Start SignedInfo -->
62
+
63
+ <element name="SignedInfo" type="ds:SignedInfoType"/>
64
+ <complexType name="SignedInfoType">
65
+ <sequence>
66
+ <element ref="ds:CanonicalizationMethod"/>
67
+ <element ref="ds:SignatureMethod"/>
68
+ <element ref="ds:Reference" maxOccurs="unbounded"/>
69
+ </sequence>
70
+ <attribute name="Id" type="ID" use="optional"/>
71
+ </complexType>
72
+
73
+ <element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType"/>
74
+ <complexType name="CanonicalizationMethodType" mixed="true">
75
+ <sequence>
76
+ <any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
77
+ <!-- (0,unbounded) elements from (1,1) namespace -->
78
+ </sequence>
79
+ <attribute name="Algorithm" type="anyURI" use="required"/>
80
+ </complexType>
81
+
82
+ <element name="SignatureMethod" type="ds:SignatureMethodType"/>
83
+ <complexType name="SignatureMethodType" mixed="true">
84
+ <sequence>
85
+ <element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
86
+ <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
87
+ <!-- (0,unbounded) elements from (1,1) external namespace -->
88
+ </sequence>
89
+ <attribute name="Algorithm" type="anyURI" use="required"/>
90
+ </complexType>
91
+
92
+ <!-- Start Reference -->
93
+
94
+ <element name="Reference" type="ds:ReferenceType"/>
95
+ <complexType name="ReferenceType">
96
+ <sequence>
97
+ <element ref="ds:Transforms" minOccurs="0"/>
98
+ <element ref="ds:DigestMethod"/>
99
+ <element ref="ds:DigestValue"/>
100
+ </sequence>
101
+ <attribute name="Id" type="ID" use="optional"/>
102
+ <attribute name="URI" type="anyURI" use="optional"/>
103
+ <attribute name="Type" type="anyURI" use="optional"/>
104
+ </complexType>
105
+
106
+ <element name="Transforms" type="ds:TransformsType"/>
107
+ <complexType name="TransformsType">
108
+ <sequence>
109
+ <element ref="ds:Transform" maxOccurs="unbounded"/>
110
+ </sequence>
111
+ </complexType>
112
+
113
+ <element name="Transform" type="ds:TransformType"/>
114
+ <complexType name="TransformType" mixed="true">
115
+ <choice minOccurs="0" maxOccurs="unbounded">
116
+ <any namespace="##other" processContents="lax"/>
117
+ <!-- (1,1) elements from (0,unbounded) namespaces -->
118
+ <element name="XPath" type="string"/>
119
+ </choice>
120
+ <attribute name="Algorithm" type="anyURI" use="required"/>
121
+ </complexType>
122
+
123
+ <!-- End Reference -->
124
+
125
+ <element name="DigestMethod" type="ds:DigestMethodType"/>
126
+ <complexType name="DigestMethodType" mixed="true">
127
+ <sequence>
128
+ <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
129
+ </sequence>
130
+ <attribute name="Algorithm" type="anyURI" use="required"/>
131
+ </complexType>
132
+
133
+ <element name="DigestValue" type="ds:DigestValueType"/>
134
+ <simpleType name="DigestValueType">
135
+ <restriction base="base64Binary"/>
136
+ </simpleType>
137
+
138
+ <!-- End SignedInfo -->
139
+
140
+ <!-- Start KeyInfo -->
141
+
142
+ <element name="KeyInfo" type="ds:KeyInfoType"/>
143
+ <complexType name="KeyInfoType" mixed="true">
144
+ <choice maxOccurs="unbounded">
145
+ <element ref="ds:KeyName"/>
146
+ <element ref="ds:KeyValue"/>
147
+ <element ref="ds:RetrievalMethod"/>
148
+ <element ref="ds:X509Data"/>
149
+ <element ref="ds:PGPData"/>
150
+ <element ref="ds:SPKIData"/>
151
+ <element ref="ds:MgmtData"/>
152
+ <any processContents="lax" namespace="##other"/>
153
+ <!-- (1,1) elements from (0,unbounded) namespaces -->
154
+ </choice>
155
+ <attribute name="Id" type="ID" use="optional"/>
156
+ </complexType>
157
+
158
+ <element name="KeyName" type="string"/>
159
+ <element name="MgmtData" type="string"/>
160
+
161
+ <element name="KeyValue" type="ds:KeyValueType"/>
162
+ <complexType name="KeyValueType" mixed="true">
163
+ <choice>
164
+ <element ref="ds:DSAKeyValue"/>
165
+ <element ref="ds:RSAKeyValue"/>
166
+ <any namespace="##other" processContents="lax"/>
167
+ </choice>
168
+ </complexType>
169
+
170
+ <element name="RetrievalMethod" type="ds:RetrievalMethodType"/>
171
+ <complexType name="RetrievalMethodType">
172
+ <sequence>
173
+ <element ref="ds:Transforms" minOccurs="0"/>
174
+ </sequence>
175
+ <attribute name="URI" type="anyURI"/>
176
+ <attribute name="Type" type="anyURI" use="optional"/>
177
+ </complexType>
178
+
179
+ <!-- Start X509Data -->
180
+
181
+ <element name="X509Data" type="ds:X509DataType"/>
182
+ <complexType name="X509DataType">
183
+ <sequence maxOccurs="unbounded">
184
+ <choice>
185
+ <element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
186
+ <element name="X509SKI" type="base64Binary"/>
187
+ <element name="X509SubjectName" type="string"/>
188
+ <element name="X509Certificate" type="base64Binary"/>
189
+ <element name="X509CRL" type="base64Binary"/>
190
+ <any namespace="##other" processContents="lax"/>
191
+ </choice>
192
+ </sequence>
193
+ </complexType>
194
+
195
+ <complexType name="X509IssuerSerialType">
196
+ <sequence>
197
+ <element name="X509IssuerName" type="string"/>
198
+ <element name="X509SerialNumber" type="integer"/>
199
+ </sequence>
200
+ </complexType>
201
+
202
+ <!-- End X509Data -->
203
+
204
+ <!-- Begin PGPData -->
205
+
206
+ <element name="PGPData" type="ds:PGPDataType"/>
207
+ <complexType name="PGPDataType">
208
+ <choice>
209
+ <sequence>
210
+ <element name="PGPKeyID" type="base64Binary"/>
211
+ <element name="PGPKeyPacket" type="base64Binary" minOccurs="0"/>
212
+ <any namespace="##other" processContents="lax" minOccurs="0"
213
+ maxOccurs="unbounded"/>
214
+ </sequence>
215
+ <sequence>
216
+ <element name="PGPKeyPacket" type="base64Binary"/>
217
+ <any namespace="##other" processContents="lax" minOccurs="0"
218
+ maxOccurs="unbounded"/>
219
+ </sequence>
220
+ </choice>
221
+ </complexType>
222
+
223
+ <!-- End PGPData -->
224
+
225
+ <!-- Begin SPKIData -->
226
+
227
+ <element name="SPKIData" type="ds:SPKIDataType"/>
228
+ <complexType name="SPKIDataType">
229
+ <sequence maxOccurs="unbounded">
230
+ <element name="SPKISexp" type="base64Binary"/>
231
+ <any namespace="##other" processContents="lax" minOccurs="0"/>
232
+ </sequence>
233
+ </complexType>
234
+
235
+ <!-- End SPKIData -->
236
+
237
+ <!-- End KeyInfo -->
238
+
239
+ <!-- Start Object (Manifest, SignatureProperty) -->
240
+
241
+ <element name="Object" type="ds:ObjectType"/>
242
+ <complexType name="ObjectType" mixed="true">
243
+ <sequence minOccurs="0" maxOccurs="unbounded">
244
+ <any namespace="##any" processContents="lax"/>
245
+ </sequence>
246
+ <attribute name="Id" type="ID" use="optional"/>
247
+ <attribute name="MimeType" type="string" use="optional"/> <!-- add a grep facet -->
248
+ <attribute name="Encoding" type="anyURI" use="optional"/>
249
+ </complexType>
250
+
251
+ <element name="Manifest" type="ds:ManifestType"/>
252
+ <complexType name="ManifestType">
253
+ <sequence>
254
+ <element ref="ds:Reference" maxOccurs="unbounded"/>
255
+ </sequence>
256
+ <attribute name="Id" type="ID" use="optional"/>
257
+ </complexType>
258
+
259
+ <element name="SignatureProperties" type="ds:SignaturePropertiesType"/>
260
+ <complexType name="SignaturePropertiesType">
261
+ <sequence>
262
+ <element ref="ds:SignatureProperty" maxOccurs="unbounded"/>
263
+ </sequence>
264
+ <attribute name="Id" type="ID" use="optional"/>
265
+ </complexType>
266
+
267
+ <element name="SignatureProperty" type="ds:SignaturePropertyType"/>
268
+ <complexType name="SignaturePropertyType" mixed="true">
269
+ <choice maxOccurs="unbounded">
270
+ <any namespace="##other" processContents="lax"/>
271
+ <!-- (1,1) elements from (1,unbounded) namespaces -->
272
+ </choice>
273
+ <attribute name="Target" type="anyURI" use="required"/>
274
+ <attribute name="Id" type="ID" use="optional"/>
275
+ </complexType>
276
+
277
+ <!-- End Object (Manifest, SignatureProperty) -->
278
+
279
+ <!-- Start Algorithm Parameters -->
280
+
281
+ <simpleType name="HMACOutputLengthType">
282
+ <restriction base="integer"/>
283
+ </simpleType>
284
+
285
+ <!-- Start KeyValue Element-types -->
286
+
287
+ <element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
288
+ <complexType name="DSAKeyValueType">
289
+ <sequence>
290
+ <sequence minOccurs="0">
291
+ <element name="P" type="ds:CryptoBinary"/>
292
+ <element name="Q" type="ds:CryptoBinary"/>
293
+ </sequence>
294
+ <element name="G" type="ds:CryptoBinary" minOccurs="0"/>
295
+ <element name="Y" type="ds:CryptoBinary"/>
296
+ <element name="J" type="ds:CryptoBinary" minOccurs="0"/>
297
+ <sequence minOccurs="0">
298
+ <element name="Seed" type="ds:CryptoBinary"/>
299
+ <element name="PgenCounter" type="ds:CryptoBinary"/>
300
+ </sequence>
301
+ </sequence>
302
+ </complexType>
303
+
304
+ <element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
305
+ <complexType name="RSAKeyValueType">
306
+ <sequence>
307
+ <element name="Modulus" type="ds:CryptoBinary"/>
308
+ <element name="Exponent" type="ds:CryptoBinary"/>
309
+ </sequence>
310
+ </complexType>
311
+
312
+ <!-- End KeyValue Element-types -->
313
+
314
+ <!-- End Signature -->
315
+
316
+ </schema>
@@ -0,0 +1,22 @@
1
+ require 'nokogiri'
2
+ require 'savon'
3
+
4
+ require_relative 'nfse_sjc/dirs'
5
+ require_relative 'nfse_sjc/config'
6
+ require_relative 'nfse_sjc/schemas'
7
+ require_relative 'nfse_sjc/errors/validation_error'
8
+ require_relative 'nfse_sjc/response_hash'
9
+ require_relative 'nfse_sjc/parser'
10
+ require_relative 'nfse_sjc/document'
11
+ require_relative 'nfse_sjc/version'
12
+ require_relative 'nfse_sjc/client'
13
+
14
+ module NfseSjc
15
+ def self.config(at: nil)
16
+ if block_given?
17
+ yield Config
18
+ else
19
+ Config.to_h(at: at)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ module NfseSjc
2
+ class Client
3
+ PARAM_KEYS = [:pretty_print_xml, :log, :wsdl, :ssl_cert_file,
4
+ :ssl_cert_key_file, :ssl_cert_key_password].freeze
5
+
6
+ def initialize(params = {})
7
+ @savon = Savon.client slice(params, *PARAM_KEYS).merge(NfseSjc.config(at: PARAM_KEYS))
8
+ @parser = Parser.new
9
+ @header = Document.new(Dirs.template('cabecalho_v3.xml.erb'), {}).to_xml.freeze
10
+ end
11
+
12
+ def call(method, params)
13
+ schema = Schemas.get_schema("#{method}.xml.erb")
14
+ schema_path = File.join Dirs.etc, 'schemas', schema
15
+ xsd = Nokogiri::XML::Schema(File.open schema_path)
16
+ document = Document.new(Dirs.template("#{method}.xml.erb"), params).to_signed_xml
17
+
18
+ errors = xsd.validate(Nokogiri::XML(document))
19
+
20
+ if errors.any?
21
+ message = errors.map do |err|
22
+ "* #{err}".gsub('{http://www.ginfes.com.br/tipos_v03.xsd}','').gsub('Element ', '')
23
+ end.join("\n")
24
+
25
+ raise NfseSjc::Errors::ValidationError.new("XML with invalid or incorrect data according to schema #{schema}, found errors:\n #{message}")
26
+ else
27
+ response = @savon.call(method, message: {
28
+ arg0: @header,
29
+ arg1: document
30
+ })
31
+
32
+ @parser.parse(response.body[:"#{method}_response"][:return])
33
+ end
34
+ end
35
+
36
+ def method_missing(name, *args, &block)
37
+ call(name, *args, &block)
38
+ end
39
+
40
+ private
41
+
42
+ def slice(hash, *keys)
43
+ keys.each_with_object({}) do |key, red|
44
+ red[key] = hash[key] if hash.has_key?(key)
45
+ end
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,31 @@
1
+ module NfseSjc
2
+ module Config
3
+ class << self
4
+ def self.default_attr(attr_name, env_path)
5
+ attr_writer attr_name
6
+ class_eval <<-RUBY
7
+ def #{attr_name}
8
+ @#{attr_name} ||= ENV['#{env_path}']
9
+ end
10
+ RUBY
11
+ end
12
+
13
+ default_attr :wsdl, 'NFSE_SJC_WSDL_URI'
14
+ default_attr :ssl_cert_file, 'NFSE_SJC_SSL_CERT_FILE'
15
+ default_attr :ssl_cert_key_file, 'NFSE_SJC_SSL_CERT_KEY_FILE'
16
+ default_attr :ssl_cert_key_password, 'NFSE_SJC_SSL_CERT_KEY_PASSWORD'
17
+ default_attr :log, 'NFSE_SJC_LOG'
18
+ default_attr :pretty_print_xml, 'NFSE_SJC_PRETTY_XML_LOG'
19
+ default_attr :xmlsec_binary_path, 'NFSE_SJC_XMLSEC_BINARY_PATH'
20
+
21
+ def to_h(at: nil)
22
+ %i(wsdl ssl_cert_file ssl_cert_key_file ssl_cert_key_password log pretty_print_xml xmlsec_binary_path).select do |prop|
23
+ at.blank? || at.include?(prop)
24
+ end.map do |meth|
25
+ val = send(meth)
26
+ [meth, val] if val
27
+ end.compact.to_h
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ module NfseSjc
2
+ module Dirs
3
+ def self.root
4
+ File.join(File.dirname(__dir__), '..')
5
+ end
6
+
7
+ def self.bin
8
+ File.join root, 'bin'
9
+ end
10
+
11
+ def self.lib
12
+ File.join root, 'lib'
13
+ end
14
+
15
+ def self.etc
16
+ File.join root, 'etc'
17
+ end
18
+
19
+ def self.template(filename)
20
+ File.join etc, 'codegen', filename
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,67 @@
1
+ require 'erubis'
2
+ require 'tempfile'
3
+
4
+ module NfseSjc
5
+ class Document
6
+ def initialize(filepath, params = {})
7
+ @params = params
8
+ @template = load_template(filepath)
9
+ end
10
+
11
+ def to_xml
12
+ @template.result(binding)
13
+ end
14
+
15
+ def to_signed_xml
16
+ unsigned_xml = to_xml
17
+
18
+ unsigned_temp_xml = Tempfile.new('unsigned-xml')
19
+ signed_temp_xml = Tempfile.new('signed-xml')
20
+ result = ''
21
+
22
+ begin
23
+ unsigned_temp_xml.write(unsigned_xml)
24
+ unsigned_temp_xml.rewind
25
+
26
+ %x{#{NfseSjc.config[:xmlsec_binary_path]} --sign --privkey-pem '#{NfseSjc.config[:ssl_cert_key_file]}','#{NfseSjc.config[:ssl_cert_file]}' --output '#{signed_temp_xml.path}' --pwd '#{NfseSjc.config[:ssl_cert_key_password]}' '#{unsigned_temp_xml.path}'}
27
+
28
+ signed_temp_xml.rewind
29
+ result = signed_temp_xml.read
30
+ ensure
31
+ signed_temp_xml.close
32
+ unsigned_temp_xml.close
33
+
34
+ signed_temp_xml.unlink
35
+ unsigned_temp_xml.unlink
36
+ end
37
+
38
+ result
39
+ end
40
+
41
+ protected
42
+
43
+ def render(filepath, params = {}, of: ::NfseSjc::Document)
44
+ of.new(NfseSjc::Dirs.template(filepath), params).to_xml
45
+ end
46
+
47
+ def param(*path, with: @params)
48
+ value = with
49
+ path.each do |segment|
50
+ value = value[segment]
51
+ break if value.nil?
52
+ end
53
+ return value
54
+ end
55
+
56
+ def if_param(*path, with: @params)
57
+ value = param(*path, with: with)
58
+ yield value unless value.nil? || (value.respond_to?(:empty) && value.empty?)
59
+ end
60
+
61
+ private
62
+ def load_template(filepath)
63
+ cachepath = File.join(Dir.tmpdir, "#{File.basename(filepath)}.cache")
64
+ Erubis::FastEruby.load_file(filepath, cachename: cachepath)
65
+ end
66
+ end
67
+ end