emites-client 0.0.2

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 (90) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +31 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +11 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +366 -0
  8. data/Rakefile +9 -0
  9. data/emites-client.gemspec +37 -0
  10. data/lib/emites.rb +44 -0
  11. data/lib/emites/client.rb +30 -0
  12. data/lib/emites/configuration.rb +12 -0
  13. data/lib/emites/entities/account.rb +8 -0
  14. data/lib/emites/entities/base.rb +9 -0
  15. data/lib/emites/entities/emitter.rb +31 -0
  16. data/lib/emites/entities/nfse.rb +29 -0
  17. data/lib/emites/entities/nfse_status.rb +15 -0
  18. data/lib/emites/entities/nfse_status_transition.rb +14 -0
  19. data/lib/emites/entities/nfse_values.rb +28 -0
  20. data/lib/emites/entities/rps.rb +9 -0
  21. data/lib/emites/entities/taker.rb +20 -0
  22. data/lib/emites/entities/taker_address.rb +21 -0
  23. data/lib/emites/entities/taker_contact.rb +9 -0
  24. data/lib/emites/entities/webhook.rb +9 -0
  25. data/lib/emites/exception.rb +11 -0
  26. data/lib/emites/http.rb +34 -0
  27. data/lib/emites/request.rb +53 -0
  28. data/lib/emites/resources/base.rb +45 -0
  29. data/lib/emites/resources/emitter.rb +98 -0
  30. data/lib/emites/resources/hooks.rb +25 -0
  31. data/lib/emites/resources/nfse.rb +173 -0
  32. data/lib/emites/resources/webhook.rb +84 -0
  33. data/lib/emites/response.rb +38 -0
  34. data/lib/emites/version.rb +3 -0
  35. data/spec/emites/client_spec.rb +45 -0
  36. data/spec/emites/configuration_spec.rb +13 -0
  37. data/spec/emites/entities/account_spec.rb +14 -0
  38. data/spec/emites/entities/base_spec.rb +28 -0
  39. data/spec/emites/entities/emitter_spec.rb +20 -0
  40. data/spec/emites/entities/nfse_spec.rb +148 -0
  41. data/spec/emites/entities/nfse_status_spec.rb +16 -0
  42. data/spec/emites/entities/nfse_status_transition_spec.rb +23 -0
  43. data/spec/emites/entities/nfse_values_spec.rb +19 -0
  44. data/spec/emites/entities/rps_spec.rb +15 -0
  45. data/spec/emites/entities/taker_address_spec.rb +18 -0
  46. data/spec/emites/entities/taker_contact_spec.rb +13 -0
  47. data/spec/emites/entities/taker_spec.rb +18 -0
  48. data/spec/emites/entities/webhook_spec.rb +14 -0
  49. data/spec/emites/exception_spec.rb +21 -0
  50. data/spec/emites/http_spec.rb +62 -0
  51. data/spec/emites/resources/base_spec.rb +96 -0
  52. data/spec/emites/resources/emitter_spec.rb +119 -0
  53. data/spec/emites/resources/nfse_spec.rb +214 -0
  54. data/spec/emites/resources/webhook_spec.rb +62 -0
  55. data/spec/emites_spec.rb +63 -0
  56. data/spec/fixtures/certificate.pfx +0 -0
  57. data/spec/shared_examples/bound_notifiers.rb +8 -0
  58. data/spec/shared_examples/entity_attributes.rb +9 -0
  59. data/spec/spec_helper.rb +38 -0
  60. data/spec/support/matchers/have_attr_accessor.rb +18 -0
  61. data/spec/vcr_cassettes/client/authenticated/false.yml +48 -0
  62. data/spec/vcr_cassettes/client/authenticated/true.yml +259 -0
  63. data/spec/vcr_cassettes/emitters/create/error.yml +57 -0
  64. data/spec/vcr_cassettes/emitters/create/success.yml +80 -0
  65. data/spec/vcr_cassettes/emitters/destroy/error.yml +47 -0
  66. data/spec/vcr_cassettes/emitters/destroy/success.yml +44 -0
  67. data/spec/vcr_cassettes/emitters/info/error.yml +47 -0
  68. data/spec/vcr_cassettes/emitters/info/success.yml +77 -0
  69. data/spec/vcr_cassettes/emitters/list/success.yml +135 -0
  70. data/spec/vcr_cassettes/emitters/partial_update/success.yml +90 -0
  71. data/spec/vcr_cassettes/emitters/search/returns_empty.yml +47 -0
  72. data/spec/vcr_cassettes/emitters/search/success.yml +76 -0
  73. data/spec/vcr_cassettes/nfse/cancel/success.yml +49 -0
  74. data/spec/vcr_cassettes/nfse/create/given_taker.yml +109 -0
  75. data/spec/vcr_cassettes/nfse/create/incomplete.yml +73 -0
  76. data/spec/vcr_cassettes/nfse/create/success.yml +112 -0
  77. data/spec/vcr_cassettes/nfse/create/without_taker.yml +73 -0
  78. data/spec/vcr_cassettes/nfse/destroy/success.yml +46 -0
  79. data/spec/vcr_cassettes/nfse/history/success.yml +83 -0
  80. data/spec/vcr_cassettes/nfse/info/success.yml +113 -0
  81. data/spec/vcr_cassettes/nfse/list/success.yml +1353 -0
  82. data/spec/vcr_cassettes/nfse/pdf/success.yml +48 -0
  83. data/spec/vcr_cassettes/nfse/status/success.yml +51 -0
  84. data/spec/vcr_cassettes/nfse/update/success.yml +113 -0
  85. data/spec/vcr_cassettes/nfse/xml/success.yml +48 -0
  86. data/spec/vcr_cassettes/webhooks/create/success.yml +53 -0
  87. data/spec/vcr_cassettes/webhooks/destroy/success.yml +46 -0
  88. data/spec/vcr_cassettes/webhooks/list/success.yml +53 -0
  89. data/spec/vcr_cassettes/webhooks/update/success.yml +52 -0
  90. metadata +390 -0
@@ -0,0 +1,62 @@
1
+ require "spec_helper"
2
+
3
+ describe Emites::Http do
4
+ let(:token) { "t0k3n" }
5
+ let!(:request) do
6
+ class_spy(Typhoeus::Request).
7
+ as_stubbed_const(transfer_nested_constants: true)
8
+ end
9
+
10
+ let!(:response) do
11
+ Typhoeus::Response.new(return_code: :ok, code: 200, body: "OK")
12
+ end
13
+
14
+ before :each do
15
+ Typhoeus.stub(/emites/).and_return(response)
16
+ allow(Typhoeus::Request).to receive(:new).
17
+ and_return(double :request, run: true, response: response)
18
+ end
19
+
20
+ subject { described_class.new(token) }
21
+
22
+ shared_examples "verbs" do |verb|
23
+ it "sends a #{verb.to_s.upcase} request to emites API" do
24
+ subject.send(verb, "/some_resource")
25
+ expect(request).to have_received(:new).
26
+ with("https://sandbox.emites.com.br/api/v1/some_resource",
27
+ method: verb,
28
+ userpwd: "#{token}:x",
29
+ accept_encoding: "gzip",
30
+ headers: {
31
+ "Accept" => "application/json",
32
+ "Content-Type" => "application/json",
33
+ "User-Agent" => Emites.configuration.user_agent
34
+ }
35
+ )
36
+ end
37
+
38
+ it "raises RequestTimeout when timed out" do
39
+ response = Typhoeus::Response.new(return_code: :operation_timedout)
40
+ Typhoeus.stub(/emites/).and_return(response)
41
+ allow(Typhoeus::Request).to receive(:new).
42
+ and_return(double :request, run: true, response: response)
43
+
44
+ expect { subject.send(verb, "/some_resource") }.to raise_error(Emites::RequestTimeout)
45
+ end
46
+
47
+ it "raises RequestError when an error occurred" do
48
+ response = Typhoeus::Response.new(return_code: :ok, code: 500, body: "")
49
+ Typhoeus.stub(/emites/).and_return(response)
50
+ allow(Typhoeus::Request).to receive(:new).
51
+ and_return(double :request, run: true, response: response)
52
+
53
+ expect { subject.send(verb, '/some_resource') }.to raise_error(Emites::RequestError)
54
+ end
55
+ end
56
+
57
+ [:get, :post, :put, :patch, :delete].each do |verb|
58
+ describe "##{verb.to_s}" do
59
+ it_behaves_like "verbs", verb
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,96 @@
1
+ require "spec_helper"
2
+
3
+ describe Emites::Resources::Base do
4
+
5
+ module Emites::Entities
6
+ class Dummy < Base
7
+ end
8
+ end
9
+
10
+ module Emites::Resources
11
+ class Dummy < Base
12
+ def parseable
13
+ response = http.get("/1mayrfq1")
14
+ parsed_body(response)
15
+ end
16
+
17
+ def fail
18
+ http.get("/fail")
19
+ end
20
+
21
+ def timeout
22
+ http.get("/timeout")
23
+ end
24
+
25
+ def notifiable(id)
26
+ "notifiable [#{id}]"
27
+ end
28
+
29
+ notify :notifiable
30
+ end
31
+ end
32
+
33
+ let(:http) { Emites::Http.new("7A75E575CFDEDB91FF7E2CE22089181A") }
34
+ let(:request) { double(body: nil, return_code: :ok) }
35
+
36
+ subject { Emites::Resources::Dummy.new(http) }
37
+
38
+ before do
39
+ allow(Emites.configuration).to receive(:url).and_return("http://requestb.in")
40
+ end
41
+
42
+ describe "#parsed_body" do
43
+ before do
44
+ allow(http).to receive(:send_request).and_return(request)
45
+ end
46
+
47
+ it "does not raise an error" do
48
+ expect{ subject.parseable }.not_to raise_error
49
+ end
50
+
51
+ it "response returns an empty hash" do
52
+ expect(subject.parseable).to eq({})
53
+ end
54
+ end
55
+
56
+ describe ".notify" do
57
+ before do
58
+ allow(http).to receive(:send_request).and_return(request)
59
+ end
60
+
61
+ class FakeListener
62
+ def call(result, args)
63
+ [result, args]
64
+ end
65
+ end
66
+
67
+ let(:listener) { FakeListener.new }
68
+
69
+ before do
70
+ Emites.subscribe("emites.dummy.notifiable", listener)
71
+ end
72
+
73
+ it "does not affect method return" do
74
+ expect(subject.notifiable(42)).to eq("notifiable [42]")
75
+ end
76
+
77
+ it "notifies listeners about event" do
78
+ expect(listener).to receive(:call).with("notifiable [42]", [42]).
79
+ and_return(["notifiable [42]", [42]])
80
+ subject.notifiable(42)
81
+ end
82
+ end
83
+
84
+ context "when request fails" do
85
+
86
+ it "raises an RequestError" do
87
+ Typhoeus.stub(/fail/).and_return(Typhoeus::Response.new(return_code: nil))
88
+ expect { subject.fail }.to raise_error(Emites::RequestError)
89
+ end
90
+
91
+ it "raises an RequestTimeout" do
92
+ Typhoeus.stub(/timeout/).and_return(Typhoeus::Response.new(return_code: :operation_timedout))
93
+ expect { subject.timeout }.to raise_error(Emites::RequestTimeout)
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,119 @@
1
+ require "spec_helper"
2
+
3
+ describe Emites::Resources::Emitter do
4
+ let(:http) { Emites::Http.new("7A75E575CFDEDB91FF7E2CE22089181A") }
5
+ let(:entity_klass) { Emites::Entities::Emitter }
6
+ let(:params) do
7
+ {
8
+ email: "wanderson.policarpo@myfreecomm.com.br",
9
+ social_reason: "My Fake, Inc",
10
+ cnpj: "01001001000113",
11
+ fancy_name: "My Fake",
12
+ city_inscription: "3304557",
13
+ state: "RJ",
14
+ city: "3",
15
+ neighborhood: "Icaraí",
16
+ street_type: "RUA",
17
+ street: "Avenida Roberto Silveira - de 472 ao fim - lado par",
18
+ number: 43,
19
+ zip_code: "24230-163",
20
+ phone: "2199999999",
21
+ certificate: Base64.encode64(File.read("spec/fixtures/certificate.pfx")),
22
+ password: "123456"
23
+ }
24
+ end
25
+
26
+ subject { described_class.new(http) }
27
+
28
+ it "has a instance of Emites::Http" do
29
+ expect(subject.http).to eq http
30
+ end
31
+
32
+ it_behaves_like "bound_notifiers", [:create, :destroy]
33
+
34
+ describe "#create" do
35
+ it "creates an emitter" do
36
+ VCR.use_cassette("emitters/create/success") do
37
+ emitter = subject.create(params)
38
+ expect(emitter).to be_a(entity_klass)
39
+ expect(emitter.cnpj).to eq(params[:cnpj])
40
+ end
41
+ end
42
+
43
+ it "returns RequestError" do
44
+ VCR.use_cassette("emitters/create/error") do
45
+ expect {
46
+ subject.create({ email: "email@example.com" })
47
+ }.to raise_error(Emites::RequestError)
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "#info" do
53
+ it "returns an Emitter instance where id is 4" do
54
+ VCR.use_cassette("emitters/info/success") do
55
+ emitter = subject.info(4)
56
+ expect(emitter).to be_a(entity_klass)
57
+ expect(emitter.cnpj).to eq("17799377000155")
58
+ end
59
+ end
60
+
61
+ it "returns RequestError" do
62
+ VCR.use_cassette("emitters/info/error") do
63
+ expect {
64
+ subject.info(2)
65
+ }.to raise_error(Emites::RequestError)
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "#list" do
71
+ it "returns an array of emitters" do
72
+ VCR.use_cassette("emitters/list/success") do
73
+ entities = subject.list
74
+ expect(entities).to be_a(Array)
75
+ entities.each do |e|
76
+ expect(e).to be_a(entity_klass)
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ describe "#search" do
83
+ it "returns an array of emitters where CNPJ is '17799377000155'" do
84
+ VCR.use_cassette("emitters/search/success") do
85
+ entities = subject.search({ cnpj: "17799377000155" })
86
+ expect(entities).to be_a(Array)
87
+ expect(entities.count).to eq(1)
88
+ entities.each do |e|
89
+ expect(e).to be_a(entity_klass)
90
+ end
91
+ end
92
+ end
93
+
94
+ it "returns empty" do
95
+ VCR.use_cassette("emitters/search/returns_empty") do
96
+ entities = subject.search({ cnpj: "1775" })
97
+ expect(entities).to be_a(Array)
98
+ expect(entities).to be_empty
99
+ end
100
+ end
101
+ end
102
+
103
+ describe "#destroy" do
104
+ it "deletes an emitter" do
105
+ VCR.use_cassette("emitters/destroy/success") do
106
+ result = subject.destroy(18)
107
+ expect(result).to be_truthy
108
+ end
109
+ end
110
+
111
+ it "returns RequestError" do
112
+ VCR.use_cassette("emitters/destroy/error") do
113
+ expect {
114
+ subject.destroy(2)
115
+ }.to raise_error(Emites::RequestError)
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,214 @@
1
+ require "spec_helper"
2
+ require "time"
3
+
4
+ describe Emites::Resources::Nfse do
5
+ let(:http) { Emites::Http.new("7A75E575CFDEDB91FF7E2CE22089181A") }
6
+ let(:entity_klass) { Emites::Entities::Nfse }
7
+ let(:params) do
8
+ {
9
+ emitter_id: 4,
10
+ rps_type: 1,
11
+ serie: "a",
12
+ emission_date: Time.now.utc.iso8601,
13
+ operation_nature: 1,
14
+ rps_situation: 1,
15
+ service_values: {
16
+ service_amount: 1000.0,
17
+ deduction_amount: 0,
18
+ retained_iss: false,
19
+ calculation_base: 1000.0,
20
+ iss_percentage: 5.00,
21
+ iss_amount: 50.0,
22
+ pis_amount: 0,
23
+ cofins_amount: 0,
24
+ inss_amount: 0,
25
+ ir_amount: 0,
26
+ csll_amount: 0,
27
+ service_item_code: "0105",
28
+ city_tax_code: "010501",
29
+ description: "RSPEC Servicos de informatica",
30
+ city_code: 3304557,
31
+ nfse_liquid_amount: 1000.0,
32
+ discount_conditioning_amount: 0
33
+ },
34
+ taker: {
35
+ cpf: "83051507121",
36
+ city_inscription: "92708711",
37
+ social_reason: "Tomador RSPEC",
38
+ address: {
39
+ street: "Feijó Júnior",
40
+ number: "535",
41
+ neighborhood: "São Pelegrino",
42
+ neighborhood_type: "COM",
43
+ city_code: 4305108,
44
+ state: "RS",
45
+ zip_code: 95110550,
46
+ city: "Caxias do Sul"
47
+ },
48
+ contact: {
49
+ phone: "32272144",
50
+ ddd: 54
51
+ }
52
+ }
53
+ }
54
+ end
55
+
56
+ subject { described_class.new(http) }
57
+
58
+ it "has a instance of Emites::Http" do
59
+ expect(subject.http).to eq http
60
+ end
61
+
62
+ it_behaves_like "bound_notifiers", [:create, :update, :cancel, :destroy]
63
+
64
+ describe "#list" do
65
+ it "returns an array of Nfse" do
66
+ VCR.use_cassette("nfse/list/success") do
67
+ nfses = subject.list
68
+ expect(nfses).to be_a(Array)
69
+ nfses.each do |e|
70
+ expect(e).to be_a(entity_klass)
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ describe "#info" do
77
+ it "returns a Nfse instance where id is 456" do
78
+ VCR.use_cassette("nfse/info/success") do
79
+ nfse = subject.info(456)
80
+ expect(nfse).to be_a(entity_klass)
81
+ expect(nfse.serie). to eq("MYFC")
82
+ expect(nfse.taker).to be_a(Emites::Entities::Taker)
83
+ end
84
+ end
85
+ end
86
+
87
+ describe "#status" do
88
+ it "returns a Nfse instance status representation" do
89
+ VCR.use_cassette("nfse/status/success") do
90
+ nfse_status = subject.status(456)
91
+ expect(nfse_status).to be_a(Emites::Entities::NfseStatus)
92
+ expect(nfse_status.status).to eq("accepted")
93
+ expect(nfse_status.description).to eq("Processado pela Sefaz")
94
+ end
95
+ end
96
+ end
97
+
98
+ describe "#history" do
99
+ it "returns a Nfse instance status history" do
100
+ VCR.use_cassette("nfse/history/success") do
101
+ nfse_status_history = subject.history(456)
102
+ expect(nfse_status_history).to be_a(Array)
103
+ nfse_status_history.each do |e|
104
+ expect(e).to be_a(Emites::Entities::NfseStatusTransition)
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "#pdf" do
111
+ it "returns a Nfse pdf" do
112
+ VCR.use_cassette("nfse/pdf/success") do
113
+ pdf_url = subject.pdf(456)
114
+ expect(pdf_url).to be_a(String)
115
+ expect(pdf_url).to match(/https?/)
116
+ end
117
+ end
118
+ end
119
+
120
+ describe "#xml" do
121
+ it "returns a Nfse xml" do
122
+ VCR.use_cassette("nfse/xml/success") do
123
+ xml_url = subject.xml(456)
124
+ expect(xml_url).to be_a(String)
125
+ expect(xml_url).to match(/https?/)
126
+ end
127
+ end
128
+ end
129
+
130
+ describe "#cancel" do
131
+ it "cancels a Nfse" do
132
+ VCR.use_cassette("nfse/cancel/success") do
133
+ nfse = subject.cancel(456)
134
+ expect(nfse).to be_a(Emites::Entities::NfseStatus)
135
+ expect(nfse.status).to eq("cancelling")
136
+ end
137
+ end
138
+ end
139
+
140
+ describe "#destroy" do
141
+ it "deletes a Nfse" do
142
+ VCR.use_cassette("nfse/destroy/success") do
143
+ result = subject.destroy(455)
144
+ expect(result).to be_truthy
145
+ end
146
+ end
147
+ end
148
+
149
+ describe "#create" do
150
+ it "creates a completely new Nfse" do
151
+ VCR.use_cassette("nfse/create/success") do
152
+ nfse = subject.create(params)
153
+ taker = nfse.taker
154
+ values = nfse.service_values
155
+
156
+ expect(nfse).to be_a(entity_klass)
157
+
158
+ expect(taker).to be_a(Emites::Entities::Taker)
159
+ expect(taker.social_reason).to eq(params[:taker][:social_reason])
160
+
161
+ expect(values).to be_a(Emites::Entities::NfseValues)
162
+ expect(values.description).to eq(params[:service_values][:description])
163
+ end
164
+ end
165
+
166
+ it "creates a Nfse where taker already exists" do
167
+ VCR.use_cassette("nfse/create/given_taker") do
168
+ params.delete(:taker)
169
+ params[:taker_id] = 6
170
+
171
+ nfse = subject.create(params)
172
+
173
+ expect(nfse.taker).to be_a(Emites::Entities::Taker)
174
+ expect(nfse.taker.social_reason).to eq("Fulano de Tal")
175
+ end
176
+ end
177
+
178
+ it "creates a Nfse without a taker" do
179
+ VCR.use_cassette("nfse/create/without_taker") do
180
+ params.delete(:taker)
181
+
182
+ nfse = subject.create(params)
183
+
184
+ expect(nfse.taker).to be_nil
185
+ end
186
+ end
187
+
188
+ it "creates an incomplete Nfse" do
189
+ VCR.use_cassette("nfse/create/incomplete") do
190
+ params.delete(:taker)
191
+ params.delete(:service_values)
192
+ params[:allow_incomplete] = true
193
+
194
+ nfse = subject.create(params)
195
+
196
+ expect(nfse).to be_a(entity_klass)
197
+ expect(nfse.status).to eq("created")
198
+ end
199
+ end
200
+ end
201
+
202
+ describe "#update" do
203
+ it "updates a Nfse" do
204
+ VCR.use_cassette("nfse/update/success") do
205
+ nfse = subject.update(564, params)
206
+
207
+ expect(nfse).to be_a(entity_klass)
208
+ expect(nfse.status).to eq("scheduled")
209
+ expect(nfse.service_values.service_amount).to eq(1000.0)
210
+ end
211
+ end
212
+ end
213
+
214
+ end