avalara 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 17daf1e3192f43bcbab3f7e4bf6d46b00ecbe831
4
+ data.tar.gz: 050df1c835d6ef337b2804f86fe6bd6444254852
5
+ SHA512:
6
+ metadata.gz: 7e12aded617978eeaaf0dd4cda53d97a42e3cb48063d0a5f4bda351d4dfdf0c2262ca6f43fd0f6f3e96a968b4993e58e9a63c309c17489efae0d5df850be78ad
7
+ data.tar.gz: 75d9aac50cae897b0c14488fbb7211738126eab8e1a05918cebcc918dd936fab7d279ddbe3bdbc934a645fb508885274b4a700fb67a38a1abeffbf8039dac1b4
@@ -6,4 +6,6 @@ rvm:
6
6
  before_script:
7
7
  - cp spec/avalara.yml.example spec/avalara.yml
8
8
  notifications:
9
- email: false
9
+ email: false
10
+ before_install:
11
+ - gem install bundler
@@ -1,8 +1,13 @@
1
- # 0.1.1 - June 11, 2015 - Added license
1
+ ## 0.2.0 - January 7, 2016 - Added Timeout
2
+
3
+ Added the ability to have set timeouts for open and read connections.
4
+ Add address validation API.
5
+
6
+ ## 0.1.1 - June 11, 2015 - Added license
2
7
 
3
8
  Added MIT license.
4
9
 
5
- # 0.1.0 - June 11, 2015 - Ruby Support
10
+ ## 0.1.0 - June 11, 2015 - Ruby Support
6
11
 
7
12
  Great work @orenf
8
13
  Removes support for ruby 1.9.2 and 1.8.7
@@ -12,18 +17,18 @@ Fixes failing specs
12
17
  APIError message now returns valid Invoice object
13
18
 
14
19
 
15
- # 0.0.3 - October 4, 2013 - Updated multi_json gem
20
+ ## 0.0.3 - October 4, 2013 - Updated multi_json gem
16
21
 
17
22
  The multi_json gem was way out of date, but https://github.com/imajes
18
23
  updated it. We also moved over to using Travis for builds.
19
24
 
20
- # 0.0.2 - May 7, 2012 - Updated tests for test endpoint.
25
+ ## 0.0.2 - May 7, 2012 - Updated tests for test endpoint.
21
26
 
22
27
  Looks like the tests were initally run against the production database
23
28
  (whops). I re-ran them against test and they're still working.
24
29
  No code changes for this, other than documenting the test endpoint.
25
30
 
26
- # 0.0.1 - February 3, 2012 - Initial Release with get_tax call
31
+ ## 0.0.1 - February 3, 2012 - Initial Release with get_tax call
27
32
 
28
33
  Not much in the way of features so far, but the rough draft of the get_tax call is in,
29
34
  as well as error and warning message handling. Still need to update the docs with it
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avalara (0.1.0)
4
+ avalara (0.2.0)
5
5
  hashie
6
6
  httparty (~> 0.13.5)
7
7
  multi_json
@@ -17,12 +17,12 @@ GEM
17
17
  diff-lcs (1.1.3)
18
18
  factory_girl (2.5.0)
19
19
  activesupport
20
- hashie (3.4.1)
21
- httparty (0.13.5)
20
+ hashie (3.4.4)
21
+ httparty (0.13.7)
22
22
  json (~> 1.8)
23
23
  multi_xml (>= 0.5.2)
24
24
  i18n (0.6.0)
25
- json (1.8.2)
25
+ json (1.8.3)
26
26
  multi_json (1.8.0)
27
27
  multi_xml (0.5.5)
28
28
  rake (0.9.2.2)
@@ -49,3 +49,6 @@ DEPENDENCIES
49
49
  rspec
50
50
  vcr
51
51
  webmock
52
+
53
+ BUNDLED WITH
54
+ 1.12.4
data/README.md CHANGED
@@ -8,26 +8,26 @@ This API provides access to the [Avalara](http://www.avalara.com/) AvaTax API.
8
8
 
9
9
  Add the gem to your `Gemfile`.
10
10
 
11
- ```
11
+ ```ruby
12
12
  gem 'avalara'
13
13
  ```
14
14
 
15
15
  Setup your Avalara credentials, either in a yml file, or as environment variables. If you want to add a yml file, it'll just need `username` and `password`:
16
16
 
17
- ```
17
+ ```yaml
18
18
  username: 'testaccount'
19
19
  password: 'testkey'
20
20
  ```
21
21
 
22
22
  You can also specify a different endpoint for development mode:
23
23
 
24
- ```
25
- https://development.avalara.net
24
+ ```yaml
25
+ endpoint: https://development.avalara.net
26
26
  ```
27
27
 
28
28
  Setup the gem in an initializer (if using Rails), or wherever if you're not. You can load in your username/password however you want, but here's a sample way to do this:
29
29
 
30
- ```
30
+ ```ruby
31
31
  file = File.new(File.join(Rails.root, 'config', 'avalara.yml'))
32
32
 
33
33
  if file.exist?
@@ -51,7 +51,7 @@ After that you should be able to use a few endpoints to Avalaras tax service. If
51
51
 
52
52
  ### Geographical Tax
53
53
 
54
- ```
54
+ ```ruby
55
55
  result = Avalara.geographical_tax('47.627935', '-122.51702', 100)
56
56
 
57
57
  # Access the details of the result, which is a Avalara::Response::Tax object
@@ -62,7 +62,7 @@ result.tax_details
62
62
 
63
63
  ### Get Tax
64
64
 
65
- ```
65
+ ```ruby
66
66
  line = Avalara::Request::Line.new({
67
67
  line_no: "1",
68
68
  destination_code: "1",
@@ -86,7 +86,7 @@ invoice = Avalara::Request::Invoice.new({
86
86
  })
87
87
 
88
88
  # You'll get back a Response::Invoice object
89
- result = Avalara.get_tax(invoice)
89
+ result = Avalara.get_tax(invoice)
90
90
 
91
91
  result.result_code
92
92
  result.total_amount
@@ -100,5 +100,6 @@ result.total_tax_calculated
100
100
  If you want to contribute, please fork this repo and make a pull request back. If you add some specs and everything still passes, we can get your contribution in! Thanks to everyone who has contributed:
101
101
 
102
102
  * [Adam Fortuna](http://github.com/adamfortuna)
103
- * [James Cox](http://github.com/adamfortuna)
103
+ * [James Cox](https://github.com/imajes)
104
104
  * [Dan Sosedoff](http://github.com/sosedoff)
105
+ * [Leo Correa](https://github.com/Tonkpils)
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.name = 'avalara'
7
7
  s.version = Avalara::VERSION
8
8
  s.authors = ['Adam Fortuna']
9
- s.email = ['adam@envylabs.com']
9
+ s.email = ['adam@codeschool.com']
10
10
  s.homepage = 'https://github.com/adamfortuna/avalara'
11
11
  s.summary = %q{A Ruby interface to the Avalara Tax API}
12
12
  s.description = %q{This library provides Ruby calls to interact with the Avalara Tax API}
@@ -27,6 +27,30 @@ module Avalara
27
27
  configuration(&block)
28
28
  end
29
29
 
30
+ def self.timeout
31
+ configuration.timeout
32
+ end
33
+
34
+ def self.timeout=(timeout)
35
+ configuration.timeout = timeout
36
+ end
37
+
38
+ def self.read_timeout
39
+ configuration.read_timeout
40
+ end
41
+
42
+ def self.read_timeout=(read_timeout)
43
+ configuration.read_timeout = read_timeout
44
+ end
45
+
46
+ def self.open_timeout
47
+ configuration.open_timeout
48
+ end
49
+
50
+ def self.open_timeout=(open_timeout)
51
+ configuration.open_timeout = open_timeout
52
+ end
53
+
30
54
  def self.endpoint
31
55
  configuration.endpoint
32
56
  end
@@ -64,10 +88,13 @@ module Avalara
64
88
  "get"
65
89
  ].join("/")
66
90
 
67
- response = API.get(uri,
68
- :headers => API.headers_for('0'),
69
- :query => {:saleamount => sales_amount},
70
- :basic_auth => authentication
91
+ response = API.get(
92
+ uri,
93
+ {
94
+ :headers => API.headers_for('0'),
95
+ :query => {:saleamount => sales_amount},
96
+ :basic_auth => authentication
97
+ }.merge!(net_settings)
71
98
  )
72
99
 
73
100
  Avalara::Response::Tax.new(response)
@@ -79,19 +106,22 @@ module Avalara
79
106
  def self.get_tax(invoice)
80
107
  uri = [endpoint, version, 'tax', 'get'].join('/')
81
108
 
82
- response = API.post(uri,
83
- :body => invoice.to_json,
84
- :headers => API.headers_for(invoice.to_json.length),
85
- :basic_auth => authentication
109
+ response = API.post(
110
+ uri,
111
+ {
112
+ :body => invoice.to_json,
113
+ :headers => API.headers_for(invoice.to_json.length),
114
+ :basic_auth => authentication
115
+ }.merge!(net_settings)
86
116
  )
87
117
 
88
- return case response.code
89
- when 200..299
90
- Response::Invoice.new(response)
91
- when 400..599
92
- raise ApiError.new(Response::Invoice.new(response))
93
- else
94
- raise ApiError.new(response)
118
+ case response.code
119
+ when 200..299
120
+ Response::Invoice.new(response)
121
+ when 400..599
122
+ raise ApiError.new(Response::Invoice.new(response))
123
+ else
124
+ raise ApiError.new(response)
95
125
  end
96
126
  rescue Timeout::Error => e
97
127
  raise TimeoutError.new(e)
@@ -101,8 +131,41 @@ module Avalara
101
131
  raise Error.new(e)
102
132
  end
103
133
 
134
+ def self.validate_address(address_hash)
135
+ uri = [endpoint, version, "address", "validate"].join("/")
136
+ response = API.get(
137
+ uri,
138
+ {
139
+ query: address_hash,
140
+ headers: API.headers_for('0'),
141
+ basic_auth: authentication
142
+ }.merge!(net_settings)
143
+ )
144
+ case response.code
145
+ when 200..299
146
+ Response::Address.new(response)
147
+ when 400..599
148
+ fail ApiError.new(Response::Address.new(response))
149
+ else
150
+ fail ApiError.new(response)
151
+ end
152
+ rescue Timeout::Error => e
153
+ raise TimeoutError.new(e)
154
+ end
155
+
104
156
  private
105
157
 
158
+ def self.net_settings
159
+ settings = {}
160
+ if timeout
161
+ settings[:read_timeout] = timeout
162
+ settings[:open_timeout] = timeout
163
+ end
164
+ settings[:read_timeout] = read_timeout if read_timeout
165
+ settings[:open_timeout] = open_timeout if open_timeout
166
+ settings
167
+ end
168
+
106
169
  def self.authentication
107
170
  { :username => username, :password => password}
108
171
  end
@@ -3,6 +3,9 @@
3
3
  class Avalara::Configuration
4
4
 
5
5
  attr_writer :endpoint
6
+ attr_accessor :timeout
7
+ attr_accessor :read_timeout
8
+ attr_accessor :open_timeout
6
9
  attr_accessor :password
7
10
  attr_accessor :username
8
11
  attr_writer :version
@@ -12,7 +15,7 @@ class Avalara::Configuration
12
15
  # set, the endpoint will default to the official production endpoint at
13
16
  # 'https://rest.avalara.net'.
14
17
  #
15
- # If you want to set this to the test endpoint, use 'https://development.avalara.net'
18
+ # If you want to set this to the test endpoint, use 'https://development.avalara.net'
16
19
  #
17
20
  # Returns the String for the API endpoint.
18
21
  #
@@ -2,11 +2,13 @@
2
2
 
3
3
  module Avalara
4
4
  module Response
5
- autoload :Invoice, 'avalara/response/invoice'
6
- autoload :Message, 'avalara/response/message'
7
- autoload :TaxLine, 'avalara/response/tax_line'
8
- autoload :TaxDetail, 'avalara/response/tax_detail'
9
- autoload :TaxAddress, 'avalara/response/tax_address'
10
- autoload :Tax, 'avalara/response/tax'
5
+ autoload :Invoice, 'avalara/response/invoice'
6
+ autoload :Message, 'avalara/response/message'
7
+ autoload :TaxLine, 'avalara/response/tax_line'
8
+ autoload :TaxDetail, 'avalara/response/tax_detail'
9
+ autoload :TaxAddress, 'avalara/response/tax_address'
10
+ autoload :Tax, 'avalara/response/tax'
11
+ autoload :AddressLine, 'avalara/response/address_line'
12
+ autoload :Address, 'avalara/response/address'
11
13
  end
12
14
  end
@@ -0,0 +1,29 @@
1
+ require "hashie/extensions/symbolize_keys"
2
+
3
+ module Avalara
4
+ module Response
5
+ class Address < Avalara::Types::Stash
6
+ property :result_code, from: :ResultCode
7
+ property :address, from: :Address
8
+ property :messages, from: :Messages
9
+
10
+ def initialize(response)
11
+ super(Hashie::Extensions::SymbolizeKeys.symbolize_keys(response))
12
+ end
13
+
14
+ def success?
15
+ result_code == "Success"
16
+ end
17
+
18
+ def Messages=(msgs)
19
+ self.messages = msgs.map do |message|
20
+ Message.new(message)
21
+ end
22
+ end
23
+
24
+ def Address=(addr)
25
+ self.address = AddressLine.new(addr)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ module Avalara
2
+ module Response
3
+ class AddressLine < Avalara::Types::Stash
4
+ property :line_1, from: :Line1
5
+ property :line_2, from: :Line2
6
+ property :line_3, from: :Line3
7
+ property :city, from: :City
8
+ property :region, from: :Region
9
+ property :postal_code, from: :PostalCode
10
+ property :country, from: :Country
11
+ property :county, from: :County
12
+ property :fips_code, from: :FipsCode
13
+ property :carrier_route, from: :CarrierRoute
14
+ property :post_net, from: :PostNet
15
+ property :address_type, from: :AddressType
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module Avalara
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -3,7 +3,7 @@
3
3
  request: !ruby/struct:VCR::Request
4
4
  method: :get
5
5
  uri: https://%{API_USERNAME}:%{API_PASSWORD}@development.avalara.net:443/1.0/tax/47.627935,-122.51702/get?saleamount=100
6
- body:
6
+ body:
7
7
  headers:
8
8
  accept:
9
9
  - application/json
@@ -0,0 +1,106 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: https://%{API_USERNAME}:%{API_PASSWORD}@development.avalara.net:443/1.0/address/validate?City=New%20York&Country=US&Line1=122%20Hudson%20St&Region=NY
6
+ body:
7
+ headers:
8
+ accept:
9
+ - application/json
10
+ content-type:
11
+ - text/json
12
+ date:
13
+ - Mon, 16 May 2016 21:16:56 GMT
14
+ user-agent:
15
+ - avalara/0.2.0 (Rubygems; Ruby 2.3.0 x86_64-darwin15)
16
+ content-length:
17
+ - '0'
18
+ response: !ruby/struct:VCR::Response
19
+ status: !ruby/struct:VCR::ResponseStatus
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ cache-control:
24
+ - private
25
+ content-type:
26
+ - text/json; charset=utf-8
27
+ server:
28
+ - Microsoft-IIS/7.5
29
+ x-aspnet-version:
30
+ - 4.0.30319
31
+ x-powered-by:
32
+ - ASP.NET
33
+ date:
34
+ - Mon, 16 May 2016 21:19:32 GMT
35
+ content-length:
36
+ - '268'
37
+ body: |
38
+ {
39
+ "ResultCode": "Success",
40
+ "Address": {
41
+ "Line1": "122 Hudson St",
42
+ "City": "New York",
43
+ "Region": "NY",
44
+ "PostalCode": "10013-2355",
45
+ "Country": "US",
46
+ "County": "NEW YORK",
47
+ "FipsCode": "3606151000",
48
+ "CarrierRoute": "C006",
49
+ "PostNet": "100132355992",
50
+ "AddressType": "H"}
51
+ }
52
+ http_version: '1.1'
53
+ - !ruby/struct:VCR::HTTPInteraction
54
+ request: !ruby/struct:VCR::Request
55
+ method: :get
56
+ uri: https://%{API_USERNAME}:%{API_PASSWORD}@development.avalara.net:443/1.0/address/validate?City=Miami&Country=US&Line1=122%20Hudson%20St&Region=NY
57
+ body:
58
+ headers:
59
+ accept:
60
+ - application/json
61
+ content-type:
62
+ - text/json
63
+ date:
64
+ - Mon, 16 May 2016 21:21:26 GMT
65
+ user-agent:
66
+ - avalara/0.2.0 (Rubygems; Ruby 2.3.0 x86_64-darwin15)
67
+ content-length:
68
+ - '0'
69
+ response: !ruby/struct:VCR::Response
70
+ status: !ruby/struct:VCR::ResponseStatus
71
+ code: 500
72
+ message: Internal Server Error
73
+ headers:
74
+ cache-control:
75
+ - private
76
+ content-type:
77
+ - text/json; charset=utf-8
78
+ server:
79
+ - Microsoft-IIS/7.5
80
+ x-aspnet-version:
81
+ - 4.0.30319
82
+ x-powered-by:
83
+ - ASP.NET
84
+ date:
85
+ - Mon, 16 May 2016 21:24:01 GMT
86
+ content-length:
87
+ - '431'
88
+ body: |
89
+ {
90
+ "ResultCode": "Error",
91
+ "Messages": [
92
+ {
93
+ "Summary": "The city could not be determined.",
94
+ "Details": "The city could not be found or determined from postal code.",
95
+ "RefersTo": "Address.City",
96
+ "Severity": "Error",
97
+ "Source": "Avalara.AvaTax.Services.Address"}
98
+ ,{
99
+ "Summary": "Address not geocoded.",
100
+ "Details": "Address cannot be geocoded.",
101
+ "RefersTo": "Address",
102
+ "Severity": "Error",
103
+ "Source": "Avalara.AvaTax.Services.Address"}
104
+ ]
105
+ }
106
+ http_version: '1.1'
@@ -0,0 +1,52 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: https://%{API_USERNAME}:%{API_PASSWORD}@development.avalara.net:443/1.0/address/validate?City=NY&Country=US&Line1=122%20Hudson%20St&Region=NY
6
+ body:
7
+ headers:
8
+ accept:
9
+ - application/json
10
+ content-type:
11
+ - text/json
12
+ date:
13
+ - Mon, 16 May 2016 21:59:13 GMT
14
+ user-agent:
15
+ - avalara/0.2.0 (Rubygems; Ruby 2.3.0 x86_64-darwin15)
16
+ content-length:
17
+ - '0'
18
+ response: !ruby/struct:VCR::Response
19
+ status: !ruby/struct:VCR::ResponseStatus
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ cache-control:
24
+ - private
25
+ content-type:
26
+ - text/json; charset=utf-8
27
+ server:
28
+ - Microsoft-IIS/7.5
29
+ x-aspnet-version:
30
+ - 4.0.30319
31
+ x-powered-by:
32
+ - ASP.NET
33
+ date:
34
+ - Mon, 16 May 2016 22:01:47 GMT
35
+ content-length:
36
+ - '268'
37
+ body: |
38
+ {
39
+ "ResultCode": "Success",
40
+ "Address": {
41
+ "Line1": "122 Hudson St",
42
+ "City": "New York",
43
+ "Region": "NY",
44
+ "PostalCode": "10013-2355",
45
+ "Country": "US",
46
+ "County": "NEW YORK",
47
+ "FipsCode": "3606151000",
48
+ "CarrierRoute": "C006",
49
+ "PostNet": "100132355992",
50
+ "AddressType": "H"}
51
+ }
52
+ http_version: '1.1'
@@ -5,6 +5,42 @@ require 'spec_helper'
5
5
  describe Avalara::Configuration do
6
6
  let(:configuration) { Avalara::Configuration.new }
7
7
 
8
+ context '#timeout' do
9
+ it 'defaults to nil' do
10
+ configuration.timeout.should == nil
11
+ end
12
+
13
+ it 'may be overridden' do
14
+ expect {
15
+ configuration.timeout = 10
16
+ }.to change(configuration, :timeout).to(10)
17
+ end
18
+ end
19
+
20
+ context '#open_timeout' do
21
+ it 'defaults to nil' do
22
+ configuration.open_timeout.should == nil
23
+ end
24
+
25
+ it 'may be overridden' do
26
+ expect {
27
+ configuration.open_timeout = 10
28
+ }.to change(configuration, :open_timeout).to(10)
29
+ end
30
+ end
31
+
32
+ context '#read_timeout' do
33
+ it 'defaults to nil' do
34
+ configuration.read_timeout.should == nil
35
+ end
36
+
37
+ it 'may be overridden' do
38
+ expect {
39
+ configuration.read_timeout = 10
40
+ }.to change(configuration, :read_timeout).to(10)
41
+ end
42
+ end
43
+
8
44
  context '#endpoint' do
9
45
  it 'defaults to https://rest.avalara.net' do
10
46
  configuration.endpoint.should == 'https://rest.avalara.net'
@@ -16,7 +52,7 @@ describe Avalara::Configuration do
16
52
  }.to change(configuration, :endpoint).to('https://example.local/')
17
53
  end
18
54
  end
19
-
55
+
20
56
  context '#version' do
21
57
  it 'defaults to 1.0' do
22
58
  configuration.version.should == '1.0'
@@ -40,7 +76,7 @@ describe Avalara::Configuration do
40
76
  }.to change(configuration, :username).to('abcdefg')
41
77
  end
42
78
  end
43
-
79
+
44
80
  context '#password' do
45
81
  it 'is unset by default' do
46
82
  configuration.password.should be_nil
@@ -52,4 +88,4 @@ describe Avalara::Configuration do
52
88
  }.to change(configuration, :password).to('abcdefg')
53
89
  end
54
90
  end
55
- end
91
+ end
@@ -54,6 +54,45 @@ describe Avalara do
54
54
  end
55
55
  end
56
56
 
57
+ describe '.timeout' do
58
+ it 'returns the configuration timeout' do
59
+ configuration.timeout = 10
60
+ Avalara.timeout.should == configuration.timeout
61
+ end
62
+
63
+ it 'overrides the configuration timeout' do
64
+ expect {
65
+ Avalara.timeout = 10
66
+ }.to change(configuration, :timeout).to(10)
67
+ end
68
+ end
69
+
70
+ describe '.open_timeout' do
71
+ it 'returns the configuration timeout' do
72
+ configuration.open_timeout = 10
73
+ Avalara.open_timeout.should == configuration.open_timeout
74
+ end
75
+
76
+ it 'overrides the configuration open_timeout' do
77
+ expect {
78
+ Avalara.open_timeout = 10
79
+ }.to change(configuration, :open_timeout).to(10)
80
+ end
81
+ end
82
+
83
+ describe '.read_timeout' do
84
+ it 'returns the configuration timeout' do
85
+ configuration.read_timeout = 10
86
+ Avalara.read_timeout.should == configuration.read_timeout
87
+ end
88
+
89
+ it 'overrides the configuration timeout' do
90
+ expect {
91
+ Avalara.read_timeout = 10
92
+ }.to change(configuration, :read_timeout).to(10)
93
+ end
94
+ end
95
+
57
96
  describe '.username' do
58
97
  it 'returns the configuration username' do
59
98
  configuration.username = 'username'
@@ -124,6 +163,55 @@ describe Avalara do
124
163
  end
125
164
  end
126
165
 
166
+ context 'with a timeout' do
167
+
168
+ before do
169
+ WebMock.allow_net_connect!
170
+ Avalara.timeout = 1
171
+ Avalara.endpoint = "http://10.255.255.1"
172
+ end
173
+
174
+ it 'raises an avalara timeout error' do
175
+ expect { subject }.to raise_error(Avalara::TimeoutError)
176
+ end
177
+ end
178
+
179
+ context 'with an open timeout' do
180
+
181
+ before do
182
+ WebMock.allow_net_connect!
183
+ Avalara.open_timeout = 1
184
+ Avalara.endpoint = "http://10.255.255.1"
185
+ end
186
+
187
+ it 'raises an avalara timeout error' do
188
+ expect { subject }.to raise_error(Avalara::TimeoutError)
189
+ end
190
+ end
191
+
192
+ context 'with a read timeout' do
193
+ let(:dummy) { TimeoutServer.new }
194
+
195
+ before(:all) do
196
+ dummy.listen(TimeoutServer::CONFIG[:BindAddress], TimeoutServer::CONFIG[:Port])
197
+ Thread.new { dummy.start }
198
+ end
199
+
200
+ before do
201
+ WebMock.allow_net_connect!
202
+ Avalara.read_timeout = 1
203
+ Avalara.endpoint = dummy.endpoint
204
+ end
205
+
206
+ after(:all) do
207
+ dummy.shutdown
208
+ end
209
+
210
+ it 'raises an avalara timeout error' do
211
+ expect { subject }.to raise_error(Avalara::TimeoutError)
212
+ end
213
+ end
214
+
127
215
  context 'on timeout' do
128
216
  it 'raises an avalara timeout error' do
129
217
  Avalara::API.should_receive(:post).and_raise(Timeout::Error)
@@ -189,6 +277,69 @@ describe Avalara do
189
277
  end
190
278
  end
191
279
 
280
+ describe ".validate_address" do
281
+ let(:address) { {
282
+ Line1: "122 Hudson St",
283
+ City: "New York",
284
+ Region: "NY",
285
+ Country: "US",
286
+ } }
287
+
288
+ def request(address)
289
+ Avalara.validate_address(address)
290
+ rescue Avalara::ApiError => e
291
+ e
292
+ end
293
+
294
+ context "on success" do
295
+
296
+ context "and an ambiguous city" do
297
+ use_vcr_cassette "validate_address/success_ambiguous"
298
+
299
+ before do
300
+ address[:City] = "NY"
301
+ end
302
+
303
+ it "resolves the ambiguity on the city" do
304
+ response = request(address)
305
+ response.address.city.should eq("New York")
306
+ end
307
+
308
+ it "is a successful request" do
309
+ response = request(address)
310
+ response.result_code.should eq("Success")
311
+ end
312
+ end
313
+ end
314
+
315
+ context "with an error returned from the api" do
316
+ use_vcr_cassette "validate_address/failure"
317
+
318
+ before do
319
+ address[:City] = "Miami"
320
+ end
321
+
322
+ it "raises an error" do
323
+ expect { Avalara.validate_address(address) }.to raise_error(Avalara::ApiError)
324
+ end
325
+
326
+ it "returns messages with details" do
327
+ response = request(address)
328
+ response.message.messages.length.should == 2
329
+
330
+ errors = response.message.messages
331
+ city_error = errors[0]
332
+ city_error.refers_to.should == "Address.City"
333
+ city_error.summary.should match(/city could not be determined/)
334
+ city_error.severity.should == "Error"
335
+
336
+ address_geocoded_error = errors[1]
337
+ address_geocoded_error.refers_to.should == "Address"
338
+ address_geocoded_error.severity.should == "Error"
339
+ end
340
+ end
341
+ end
342
+
192
343
  ## Missing VCR
193
344
  describe '.geographical_tax' do
194
345
  let(:latitude) { '47.627935' }
@@ -14,4 +14,4 @@ RSpec.configure do |config|
14
14
  config.mock_with :rspec
15
15
  config.filter_run :focus => true
16
16
  config.run_all_when_everything_filtered = true
17
- end
17
+ end
@@ -35,4 +35,4 @@ end
35
35
 
36
36
  RSpec.configure do |config|
37
37
  config.extend ConfigurationSpecHelpers
38
- end
38
+ end
@@ -0,0 +1,28 @@
1
+ require 'webrick'
2
+
3
+ class BlackHole
4
+ def self.method_missing(*args)
5
+ self
6
+ end
7
+ end
8
+
9
+ class TimeoutServer < WEBrick::HTTPServer
10
+ CONFIG = {
11
+ BindAddress: '127.0.0.1',
12
+ Port: 5000,
13
+ AccessLog: BlackHole,
14
+ Logger: BlackHole,
15
+ DoNotListen: true
16
+ }.freeze
17
+
18
+ def initialize(options = {})
19
+ super(CONFIG)
20
+ mount_proc('/', ->(req, res) {
21
+ sleep 2
22
+ })
23
+ end
24
+
25
+ def endpoint
26
+ "http://#{config[:BindAddress]}:#{config[:Port]}"
27
+ end
28
+ end
metadata CHANGED
@@ -1,140 +1,123 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: avalara
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Adam Fortuna
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2015-06-11 00:00:00.000000000 Z
11
+ date: 2016-06-12 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: hashie
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: httparty
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ~>
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
33
  version: 0.13.5
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ~>
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
40
  version: 0.13.5
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: multi_json
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: vcr
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - ">="
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - ">="
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: webmock
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - ">="
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - ">="
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: rspec
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ! '>='
87
+ - - ">="
100
88
  - !ruby/object:Gem::Version
101
89
  version: '0'
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ! '>='
94
+ - - ">="
108
95
  - !ruby/object:Gem::Version
109
96
  version: '0'
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: factory_girl
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
- - - ! '>='
101
+ - - ">="
116
102
  - !ruby/object:Gem::Version
117
103
  version: '0'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
- - - ! '>='
108
+ - - ">="
124
109
  - !ruby/object:Gem::Version
125
110
  version: '0'
126
111
  description: This library provides Ruby calls to interact with the Avalara Tax API
127
112
  email:
128
- - adam@envylabs.com
113
+ - adam@codeschool.com
129
114
  executables: []
130
115
  extensions: []
131
116
  extra_rdoc_files: []
132
117
  files:
133
- - .gitignore
134
- - .ruby-gemset
135
- - .ruby-version
136
- - .travis.yml
137
- - Changelog.md
118
+ - ".gitignore"
119
+ - ".travis.yml"
120
+ - CHANGELOG.md
138
121
  - Gemfile
139
122
  - Gemfile.lock
140
123
  - LICENSE
@@ -152,6 +135,8 @@ files:
152
135
  - lib/avalara/request/invoice.rb
153
136
  - lib/avalara/request/line.rb
154
137
  - lib/avalara/response.rb
138
+ - lib/avalara/response/address.rb
139
+ - lib/avalara/response/address_line.rb
155
140
  - lib/avalara/response/invoice.rb
156
141
  - lib/avalara/response/message.rb
157
142
  - lib/avalara/response/tax.rb
@@ -170,6 +155,8 @@ files:
170
155
  - spec/fixtures/net/geographical_tax_no_sales.yml
171
156
  - spec/fixtures/net/get_tax/failure.yml
172
157
  - spec/fixtures/net/get_tax/success.yml
158
+ - spec/fixtures/net/validate_address/failure.yml
159
+ - spec/fixtures/net/validate_address/success_ambiguous.yml
173
160
  - spec/models/avalara/configuration_spec.rb
174
161
  - spec/models/avalara/request/address_spec.rb
175
162
  - spec/models/avalara/request/detail_level_spec.rb
@@ -179,31 +166,31 @@ files:
179
166
  - spec/spec_helper.rb
180
167
  - spec/support/avalara.rb
181
168
  - spec/support/factory_girl.rb
169
+ - spec/support/timeout_server.rb
182
170
  - spec/support/vcr.rb
183
171
  homepage: https://github.com/adamfortuna/avalara
184
172
  licenses:
185
173
  - MIT
174
+ metadata: {}
186
175
  post_install_message:
187
176
  rdoc_options: []
188
177
  require_paths:
189
178
  - lib
190
179
  required_ruby_version: !ruby/object:Gem::Requirement
191
- none: false
192
180
  requirements:
193
- - - ! '>='
181
+ - - ">="
194
182
  - !ruby/object:Gem::Version
195
183
  version: '0'
196
184
  required_rubygems_version: !ruby/object:Gem::Requirement
197
- none: false
198
185
  requirements:
199
- - - ! '>='
186
+ - - ">="
200
187
  - !ruby/object:Gem::Version
201
188
  version: '0'
202
189
  requirements: []
203
190
  rubyforge_project:
204
- rubygems_version: 1.8.23.2
191
+ rubygems_version: 2.6.4
205
192
  signing_key:
206
- specification_version: 3
193
+ specification_version: 4
207
194
  summary: A Ruby interface to the Avalara Tax API
208
195
  test_files:
209
196
  - spec/avalara.yml.example
@@ -214,6 +201,8 @@ test_files:
214
201
  - spec/fixtures/net/geographical_tax_no_sales.yml
215
202
  - spec/fixtures/net/get_tax/failure.yml
216
203
  - spec/fixtures/net/get_tax/success.yml
204
+ - spec/fixtures/net/validate_address/failure.yml
205
+ - spec/fixtures/net/validate_address/success_ambiguous.yml
217
206
  - spec/models/avalara/configuration_spec.rb
218
207
  - spec/models/avalara/request/address_spec.rb
219
208
  - spec/models/avalara/request/detail_level_spec.rb
@@ -223,4 +212,6 @@ test_files:
223
212
  - spec/spec_helper.rb
224
213
  - spec/support/avalara.rb
225
214
  - spec/support/factory_girl.rb
215
+ - spec/support/timeout_server.rb
226
216
  - spec/support/vcr.rb
217
+ has_rdoc:
@@ -1 +0,0 @@
1
- avalara