taxjar-ruby 2.5.0 → 3.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.
- checksums.yaml +5 -5
- data/.travis.yml +2 -7
- data/CHANGELOG.md +25 -2
- data/README.md +524 -332
- data/lib/taxjar/api/request.rb +18 -12
- data/lib/taxjar/client.rb +8 -1
- data/lib/taxjar/error.rb +9 -0
- data/lib/taxjar/order.rb +1 -0
- data/lib/taxjar/refund.rb +1 -0
- data/lib/taxjar/tax.rb +1 -0
- data/lib/taxjar/version.rb +3 -3
- data/spec/fixtures/order.json +1 -0
- data/spec/fixtures/refund.json +1 -0
- data/spec/fixtures/taxes.json +1 -0
- data/spec/fixtures/taxes_canada.json +1 -0
- data/spec/fixtures/taxes_international.json +1 -0
- data/spec/taxjar/api/api_spec.rb +4 -0
- data/spec/taxjar/api/order_spec.rb +6 -0
- data/spec/taxjar/api/refund_spec.rb +6 -0
- data/spec/taxjar/api/request_spec.rb +70 -10
- data/spec/taxjar/client_spec.rb +4 -4
- data/taxjar-ruby.gemspec +3 -3
- metadata +14 -9
data/lib/taxjar/api/request.rb
CHANGED
@@ -28,8 +28,15 @@ module Taxjar
|
|
28
28
|
def perform
|
29
29
|
options_key = [:get, :delete].include?(@request_method) ? :params : :json
|
30
30
|
response = build_http_client.request(request_method, uri.to_s, options_key => @options)
|
31
|
-
response_body =
|
32
|
-
|
31
|
+
response_body =
|
32
|
+
begin
|
33
|
+
symbolize_keys!(response.parse(:json))
|
34
|
+
rescue JSON::ParserError
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
fail_or_return_response_body(response, response_body)
|
38
|
+
rescue HTTP::Error => e
|
39
|
+
raise Taxjar::Error, e
|
33
40
|
end
|
34
41
|
|
35
42
|
private
|
@@ -67,16 +74,15 @@ module Taxjar
|
|
67
74
|
object
|
68
75
|
end
|
69
76
|
|
70
|
-
def fail_or_return_response_body(
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
klass.from_response(body)
|
77
|
+
def fail_or_return_response_body(response, body)
|
78
|
+
if body.nil?
|
79
|
+
fail(Taxjar::Error.for_json_parse_error(response.code))
|
80
|
+
elsif response.status.success?
|
81
|
+
body[object_key.to_sym]
|
82
|
+
elsif !(klass = Taxjar::Error::ERRORS[response.code]).nil?
|
83
|
+
fail(klass.from_response(body))
|
84
|
+
else
|
85
|
+
fail(Taxjar::Error.from_response_code(response.code))
|
80
86
|
end
|
81
87
|
end
|
82
88
|
end
|
data/lib/taxjar/client.rb
CHANGED
@@ -38,7 +38,14 @@ module Taxjar
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def user_agent
|
41
|
-
|
41
|
+
def platform
|
42
|
+
(`uname -a` || '').strip
|
43
|
+
rescue Errno::ENOENT, Errno::ENOMEM
|
44
|
+
''
|
45
|
+
end
|
46
|
+
ruby_version = "ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
47
|
+
openSSL_version = OpenSSL::OPENSSL_LIBRARY_VERSION
|
48
|
+
"TaxJar/Ruby (#{platform}; #{ruby_version}; #{openSSL_version}) taxjar-ruby/#{Taxjar::Version}"
|
42
49
|
end
|
43
50
|
end
|
44
51
|
end
|
data/lib/taxjar/error.rb
CHANGED
@@ -61,6 +61,15 @@ module Taxjar
|
|
61
61
|
new(message, code)
|
62
62
|
end
|
63
63
|
|
64
|
+
def from_response_code(code)
|
65
|
+
message = HTTP::Response::Status::REASONS[code] || "Unknown Error"
|
66
|
+
new(message, code)
|
67
|
+
end
|
68
|
+
|
69
|
+
def for_json_parse_error(code)
|
70
|
+
ServerError.new("Couldn't parse response as JSON.", code)
|
71
|
+
end
|
72
|
+
|
64
73
|
end
|
65
74
|
|
66
75
|
def initialize(message = '', code = nil)
|
data/lib/taxjar/order.rb
CHANGED
data/lib/taxjar/refund.rb
CHANGED
@@ -9,6 +9,7 @@ module Taxjar
|
|
9
9
|
attribute :transaction_date, :string
|
10
10
|
attribute :transaction_reference_id, :string
|
11
11
|
attribute :provider, :string
|
12
|
+
attribute :exemption_type, :string
|
12
13
|
attribute :from_country, :string
|
13
14
|
attribute :from_zip, :string
|
14
15
|
attribute :from_state, :string
|
data/lib/taxjar/tax.rb
CHANGED
@@ -12,6 +12,7 @@ module Taxjar
|
|
12
12
|
attribute :has_nexus, :boolean
|
13
13
|
attribute :freight_taxable, :boolean
|
14
14
|
attribute :tax_source, :string
|
15
|
+
attribute :exemption_type, :string
|
15
16
|
|
16
17
|
object_attr_reader Taxjar::Jurisdictions, :jurisdictions
|
17
18
|
object_attr_reader Taxjar::Breakdown, :breakdown
|
data/lib/taxjar/version.rb
CHANGED
data/spec/fixtures/order.json
CHANGED
data/spec/fixtures/refund.json
CHANGED
data/spec/fixtures/taxes.json
CHANGED
data/spec/taxjar/api/api_spec.rb
CHANGED
@@ -168,6 +168,7 @@ describe Taxjar::API do
|
|
168
168
|
:to_zip => '07446',
|
169
169
|
:amount => 16.50,
|
170
170
|
:shipping => 1.5,
|
171
|
+
:exemption_type => 'non_exempt',
|
171
172
|
:line_items => [{:line_item => {:id => '1',
|
172
173
|
:quantity => 1,
|
173
174
|
:unit_price => 15.0,
|
@@ -191,6 +192,7 @@ describe Taxjar::API do
|
|
191
192
|
expect(tax.has_nexus).to eq(true)
|
192
193
|
expect(tax.freight_taxable).to eq(true)
|
193
194
|
expect(tax.tax_source).to eq('destination')
|
195
|
+
expect(tax.exemption_type).to eq('non_exempt')
|
194
196
|
end
|
195
197
|
|
196
198
|
it 'allows access to jurisdictions' do
|
@@ -275,6 +277,7 @@ describe Taxjar::API do
|
|
275
277
|
expect(tax.has_nexus).to eq(true)
|
276
278
|
expect(tax.freight_taxable).to eq(true)
|
277
279
|
expect(tax.tax_source).to eq('destination')
|
280
|
+
expect(tax.exemption_type).to eq('non_exempt')
|
278
281
|
end
|
279
282
|
|
280
283
|
it 'allows access to jurisdictions' do
|
@@ -330,6 +333,7 @@ describe Taxjar::API do
|
|
330
333
|
expect(tax.has_nexus).to eq(true)
|
331
334
|
expect(tax.freight_taxable).to eq(true)
|
332
335
|
expect(tax.tax_source).to eq('destination')
|
336
|
+
expect(tax.exemption_type).to eq('non_exempt')
|
333
337
|
end
|
334
338
|
|
335
339
|
it 'allows access to jurisdictions' do
|
@@ -71,6 +71,7 @@ describe Taxjar::API::Order do
|
|
71
71
|
expect(order.user_id).to eq(10649)
|
72
72
|
expect(order.transaction_date).to eq('2015-05-14T00:00:00Z')
|
73
73
|
expect(order.provider).to eq('api')
|
74
|
+
expect(order.exemption_type).to eq('non_exempt')
|
74
75
|
expect(order.from_country).to eq('US')
|
75
76
|
expect(order.from_zip).to eq('93107')
|
76
77
|
expect(order.from_state).to eq('CA')
|
@@ -107,6 +108,7 @@ describe Taxjar::API::Order do
|
|
107
108
|
@order = {:transaction_id => '123',
|
108
109
|
:transaction_date => '2015/05/14',
|
109
110
|
:provider => 'api',
|
111
|
+
:exemption_type => 'non_exempt',
|
110
112
|
:to_country => 'US',
|
111
113
|
:to_zip => '90002',
|
112
114
|
:to_city => 'Los Angeles',
|
@@ -137,6 +139,7 @@ describe Taxjar::API::Order do
|
|
137
139
|
expect(order.user_id).to eq(10649)
|
138
140
|
expect(order.transaction_date).to eq("2015-05-14T00:00:00Z")
|
139
141
|
expect(order.provider).to eq('api')
|
142
|
+
expect(order.exemption_type).to eq('non_exempt')
|
140
143
|
expect(order.from_country).to eq('US')
|
141
144
|
expect(order.from_zip).to eq('93107')
|
142
145
|
expect(order.from_state).to eq('CA')
|
@@ -174,6 +177,7 @@ describe Taxjar::API::Order do
|
|
174
177
|
@order = {:transaction_id => '123',
|
175
178
|
:amount => 17.95,
|
176
179
|
:shipping => 2.0,
|
180
|
+
:exemption_type => 'non_exempt',
|
177
181
|
:line_items => [{:id => 1,
|
178
182
|
:quantity => 1,
|
179
183
|
:product_identifier => '12-34243-0',
|
@@ -197,6 +201,7 @@ describe Taxjar::API::Order do
|
|
197
201
|
expect(order.user_id).to eq(10649)
|
198
202
|
expect(order.transaction_date).to eq("2015-05-14T00:00:00Z")
|
199
203
|
expect(order.provider).to eq('api')
|
204
|
+
expect(order.exemption_type).to eq('non_exempt')
|
200
205
|
expect(order.from_country).to eq('US')
|
201
206
|
expect(order.from_zip).to eq('93107')
|
202
207
|
expect(order.from_state).to eq('CA')
|
@@ -244,6 +249,7 @@ describe Taxjar::API::Order do
|
|
244
249
|
expect(order.user_id).to eq(10649)
|
245
250
|
expect(order.transaction_date).to eq("2015-05-14T00:00:00Z")
|
246
251
|
expect(order.provider).to eq('api')
|
252
|
+
expect(order.exemption_type).to eq('non_exempt')
|
247
253
|
expect(order.from_country).to eq('US')
|
248
254
|
expect(order.from_zip).to eq('93107')
|
249
255
|
expect(order.from_state).to eq('CA')
|
@@ -72,6 +72,7 @@ describe Taxjar::API::Refund do
|
|
72
72
|
expect(refund.transaction_date).to eq("2015-05-14T00:00:00Z")
|
73
73
|
expect(refund.transaction_reference_id).to eq("123")
|
74
74
|
expect(refund.provider).to eql('api')
|
75
|
+
expect(refund.exemption_type).to eq('non_exempt')
|
75
76
|
expect(refund.from_country).to eq('US')
|
76
77
|
expect(refund.from_zip).to eq('93107')
|
77
78
|
expect(refund.from_state).to eq('CA')
|
@@ -109,6 +110,7 @@ describe Taxjar::API::Refund do
|
|
109
110
|
:transaction_date => '2015/05/14',
|
110
111
|
:transaction_reference_id => '123',
|
111
112
|
:provider => 'api',
|
113
|
+
:exemption_type => 'non_exempt',
|
112
114
|
:to_country => 'US',
|
113
115
|
:to_zip => '90002',
|
114
116
|
:to_state => 'CA',
|
@@ -140,6 +142,7 @@ describe Taxjar::API::Refund do
|
|
140
142
|
expect(refund.transaction_date).to eq("2015-05-14T00:00:00Z")
|
141
143
|
expect(refund.transaction_reference_id).to eq("123")
|
142
144
|
expect(refund.provider).to eq('api')
|
145
|
+
expect(refund.exemption_type).to eq('non_exempt')
|
143
146
|
expect(refund.from_country).to eq('US')
|
144
147
|
expect(refund.from_zip).to eq('93107')
|
145
148
|
expect(refund.from_state).to eq('CA')
|
@@ -178,6 +181,7 @@ describe Taxjar::API::Refund do
|
|
178
181
|
:amount => 17.95,
|
179
182
|
:shipping => 2.0,
|
180
183
|
:sales_tax => 0.95,
|
184
|
+
:exemption_type => 'non_exempt',
|
181
185
|
:line_items => [{:quantity => 1,
|
182
186
|
:product_identifier => '12-34243-9',
|
183
187
|
:description => 'Heavy Widget',
|
@@ -201,6 +205,7 @@ describe Taxjar::API::Refund do
|
|
201
205
|
expect(refund.transaction_date).to eq("2015-05-14T00:00:00Z")
|
202
206
|
expect(refund.transaction_reference_id).to eq("123")
|
203
207
|
expect(refund.provider).to eq('api')
|
208
|
+
expect(refund.exemption_type).to eq('non_exempt')
|
204
209
|
expect(refund.from_country).to eq('US')
|
205
210
|
expect(refund.from_zip).to eq('93107')
|
206
211
|
expect(refund.from_state).to eq('CA')
|
@@ -249,6 +254,7 @@ describe Taxjar::API::Refund do
|
|
249
254
|
expect(refund.transaction_date).to eq("2015-05-14T00:00:00Z")
|
250
255
|
expect(refund.transaction_reference_id).to eq("123")
|
251
256
|
expect(refund.provider).to eq('api')
|
257
|
+
expect(refund.exemption_type).to eq('non_exempt')
|
252
258
|
expect(refund.from_country).to eq('US')
|
253
259
|
expect(refund.from_zip).to eq('93107')
|
254
260
|
expect(refund.from_state).to eq('CA')
|
@@ -41,7 +41,7 @@ describe Taxjar::API::Request do
|
|
41
41
|
it 'should return headers' do
|
42
42
|
expect(subject).to respond_to(:headers)
|
43
43
|
expect(subject.headers).to be_instance_of(Hash)
|
44
|
-
expect(subject.headers[:user_agent]).to match(
|
44
|
+
expect(subject.headers[:user_agent]).to match(/^TaxJar\/Ruby \(.+\) taxjar-ruby\/\d+\.\d+\.\d+$/)
|
45
45
|
expect(subject.headers[:authorization]).to eq('Bearer AK')
|
46
46
|
end
|
47
47
|
|
@@ -52,7 +52,7 @@ describe Taxjar::API::Request do
|
|
52
52
|
subject = Taxjar::API::Request.new(client, :get, '/api_path', 'object')
|
53
53
|
expect(subject).to respond_to(:headers)
|
54
54
|
expect(subject.headers).to be_instance_of(Hash)
|
55
|
-
expect(subject.headers[:user_agent]).to match(
|
55
|
+
expect(subject.headers[:user_agent]).to match(/^TaxJar\/Ruby \(.+\) taxjar-ruby\/\d+\.\d+\.\d+$/)
|
56
56
|
expect(subject.headers[:authorization]).to eq('Bearer AK')
|
57
57
|
expect(subject.headers['X-TJ-Expected-Response']).to eq(422)
|
58
58
|
end
|
@@ -124,8 +124,7 @@ describe Taxjar::API::Request do
|
|
124
124
|
it "runs through the proxy" do
|
125
125
|
stub_request(:get, "https://api.taxjar.com/api_path").
|
126
126
|
with(:headers => {'Authorization'=>'Bearer AK', 'Connection'=>'close',
|
127
|
-
'Host'=>'api.taxjar.com'
|
128
|
-
'User-Agent'=>"TaxjarRubyGem/#{Taxjar::Version.to_s}"}).
|
127
|
+
'Host'=>'api.taxjar.com'}).
|
129
128
|
to_return(:status => 200, :body => '{"object": {"id": "3"}}',
|
130
129
|
:headers => {content_type: 'application/json; charset=UTF-8'})
|
131
130
|
|
@@ -138,8 +137,7 @@ describe Taxjar::API::Request do
|
|
138
137
|
it 'should return a body if no errors' do
|
139
138
|
stub_request(:get, "https://api.taxjar.com/api_path").
|
140
139
|
with(:headers => {'Authorization'=>'Bearer AK', 'Connection'=>'close',
|
141
|
-
'Host'=>'api.taxjar.com'
|
142
|
-
'User-Agent'=>"TaxjarRubyGem/#{Taxjar::Version.to_s}"}).
|
140
|
+
'Host'=>'api.taxjar.com'}).
|
143
141
|
to_return(:status => 200, :body => '{"object": {"id": "3"}}',
|
144
142
|
:headers => {content_type: 'application/json; charset=UTF-8'})
|
145
143
|
|
@@ -159,8 +157,7 @@ describe Taxjar::API::Request do
|
|
159
157
|
with(:body => "{\"city\":\"New York\"}",
|
160
158
|
:headers => {'Authorization'=>'Bearer AK', 'Connection'=>'close',
|
161
159
|
'Content-Type'=>'application/json; charset=UTF-8',
|
162
|
-
'Host'=>'api.taxjar.com'
|
163
|
-
'User-Agent'=>"TaxjarRubyGem/#{Taxjar::Version.to_s}"}).
|
160
|
+
'Host'=>'api.taxjar.com'}).
|
164
161
|
to_return(:status => 200, :body => '{"object": {"id": "3"}}',
|
165
162
|
:headers => {content_type: 'application/json; charset=UTF-8'})
|
166
163
|
|
@@ -168,13 +165,40 @@ describe Taxjar::API::Request do
|
|
168
165
|
end
|
169
166
|
end
|
170
167
|
|
168
|
+
it 'handles unexpected Content-Type responses' do
|
169
|
+
stub_request(:get, "https://api.taxjar.com/api_path").
|
170
|
+
with(:headers => {'Authorization'=>'Bearer AK', 'Connection'=>'close',
|
171
|
+
'Host'=>'api.taxjar.com'}).
|
172
|
+
to_return(:status => 200, :body => 'Something unexpected',
|
173
|
+
:headers => {content_type: 'text/html; charset=UTF-8'})
|
174
|
+
|
175
|
+
expect{subject.perform}.to raise_error(Taxjar::Error::ServerError)
|
176
|
+
end
|
177
|
+
|
178
|
+
[
|
179
|
+
HTTP::Error,
|
180
|
+
HTTP::ConnectionError,
|
181
|
+
HTTP::RequestError,
|
182
|
+
HTTP::ResponseError,
|
183
|
+
HTTP::StateError,
|
184
|
+
HTTP::TimeoutError,
|
185
|
+
HTTP::HeaderError
|
186
|
+
].each do |http_error_class|
|
187
|
+
context "#{http_error_class}" do
|
188
|
+
it "is classified as a Taxjar::Error" do
|
189
|
+
stub_request(:get, "https://api.taxjar.com/api_path").to_raise(http_error_class)
|
190
|
+
|
191
|
+
expect{subject.perform}.to raise_error(Taxjar::Error)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
171
196
|
Taxjar::Error::ERRORS.each do |status, exception|
|
172
197
|
context "when HTTP status is #{status}" do
|
173
198
|
it "raises #{exception}" do
|
174
199
|
stub_request(:get, "https://api.taxjar.com/api_path").
|
175
200
|
with(:headers => {'Authorization'=>'Bearer AK', 'Connection'=>'close',
|
176
|
-
'Host'=>'api.taxjar.com'
|
177
|
-
'User-Agent'=>"TaxjarRubyGem/#{Taxjar::Version.to_s}"}).
|
201
|
+
'Host'=>'api.taxjar.com'}).
|
178
202
|
to_return(:status => status,
|
179
203
|
:body => '{"error": "Not Acceptable",
|
180
204
|
"detail": "error explanation",
|
@@ -185,5 +209,41 @@ describe Taxjar::API::Request do
|
|
185
209
|
end
|
186
210
|
end
|
187
211
|
end
|
212
|
+
|
213
|
+
context "when HTTP status is 502" do
|
214
|
+
it "raises Taxjar::Error" do
|
215
|
+
stub_request(:get, "https://api.taxjar.com/api_path").
|
216
|
+
with(:headers => {'Authorization'=>'Bearer AK', 'Connection'=>'close',
|
217
|
+
'Host'=>'api.taxjar.com'}).
|
218
|
+
to_return(:status => 502,
|
219
|
+
:body => '{}',
|
220
|
+
:headers => {content_type: 'application/json; charset=UTF-8'})
|
221
|
+
|
222
|
+
expect{subject.perform}.to raise_error(
|
223
|
+
an_instance_of(Taxjar::Error).and having_attributes({
|
224
|
+
"message" => "Bad Gateway",
|
225
|
+
"code" => 502
|
226
|
+
})
|
227
|
+
)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "when HTTP status is 5xx" do
|
232
|
+
it "raises Taxjar::Error" do
|
233
|
+
stub_request(:get, "https://api.taxjar.com/api_path").
|
234
|
+
with(:headers => {'Authorization'=>'Bearer AK', 'Connection'=>'close',
|
235
|
+
'Host'=>'api.taxjar.com'}).
|
236
|
+
to_return(:status => 509,
|
237
|
+
:body => '{}',
|
238
|
+
:headers => {content_type: 'application/json; charset=UTF-8'})
|
239
|
+
|
240
|
+
expect{subject.perform}.to raise_error(
|
241
|
+
an_instance_of(Taxjar::Error).and having_attributes({
|
242
|
+
"message" => "Unknown Error",
|
243
|
+
"code" => 509
|
244
|
+
})
|
245
|
+
)
|
246
|
+
end
|
247
|
+
end
|
188
248
|
end
|
189
249
|
end
|
data/spec/taxjar/client_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
describe Taxjar::Client do
|
4
|
-
describe '#api_key?' do
|
4
|
+
describe '#api_key?' do
|
5
5
|
it 'returns true if api_key is present' do
|
6
6
|
client = Taxjar::Client.new(api_key: 'AK')
|
7
7
|
expect(client.api_key?).to be true
|
@@ -25,14 +25,14 @@ describe Taxjar::Client do
|
|
25
25
|
client.set_api_config('api_url', 'https://api.sandbox.taxjar.com')
|
26
26
|
expect(client.api_url).to eq('https://api.sandbox.taxjar.com')
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
it 'sets new custom headers' do
|
30
30
|
client = Taxjar::Client.new(api_key: 'AK')
|
31
31
|
client.set_api_config('headers', { 'X-TJ-Expected-Response' => 422 })
|
32
32
|
expect(client.headers).to eq({ 'X-TJ-Expected-Response' => 422 })
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
describe "#get_api_config" do
|
37
37
|
it 'gets a config value' do
|
38
38
|
client = Taxjar::Client.new(api_key: 'AK')
|
@@ -44,7 +44,7 @@ describe Taxjar::Client do
|
|
44
44
|
describe '#user_agent' do
|
45
45
|
it 'returns string with version' do
|
46
46
|
client = Taxjar::Client.new(api_key: 'AK')
|
47
|
-
expect(client.user_agent).to
|
47
|
+
expect(client.user_agent).to match(/^TaxJar\/Ruby \(.+\) taxjar-ruby\/\d+\.\d+\.\d+$/)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|