avalara 0.0.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.
- data/.gitignore +1 -0
- data/.rvmrc +1 -0
- data/CHANGELOG +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +71 -0
- data/LICENSE +20 -0
- data/README +5 -0
- data/avalara.gemspec +28 -0
- data/lib/avalara.rb +101 -0
- data/lib/avalara/api.rb +23 -0
- data/lib/avalara/configuration.rb +29 -0
- data/lib/avalara/errors.rb +8 -0
- data/lib/avalara/parser.rb +41 -0
- data/lib/avalara/request.rb +11 -0
- data/lib/avalara/request/address.rb +19 -0
- data/lib/avalara/request/detail_level.rb +13 -0
- data/lib/avalara/request/invoice.rb +46 -0
- data/lib/avalara/request/line.rb +21 -0
- data/lib/avalara/response.rb +11 -0
- data/lib/avalara/response/invoice.rb +48 -0
- data/lib/avalara/response/message.rb +13 -0
- data/lib/avalara/response/tax_address.rb +16 -0
- data/lib/avalara/response/tax_detail.rb +16 -0
- data/lib/avalara/response/tax_line.rb +25 -0
- data/lib/avalara/types.rb +8 -0
- data/lib/avalara/types/date.rb +10 -0
- data/lib/avalara/types/stash.rb +28 -0
- data/lib/avalara/version.rb +5 -0
- data/spec/avalara.yml.example +2 -0
- data/spec/factories/addresses.rb +13 -0
- data/spec/factories/detail_levels.rb +7 -0
- data/spec/factories/invoices.rb +17 -0
- data/spec/factories/lines.rb +14 -0
- data/spec/fixtures/net/geographical_tax_no_sales.yml +95 -0
- data/spec/fixtures/net/get_tax/failure.yml +68 -0
- data/spec/fixtures/net/get_tax/success.yml +106 -0
- data/spec/models/avalara/configuration_spec.rb +55 -0
- data/spec/models/avalara/request/address_spec.rb +24 -0
- data/spec/models/avalara/request/detail_level_spec.rb +18 -0
- data/spec/models/avalara/request/invoice_spec.rb +33 -0
- data/spec/models/avalara/request/line_spec.rb +25 -0
- data/spec/models/avalara_spec.rb +204 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/avalara.rb +38 -0
- data/spec/support/factory_girl.rb +20 -0
- data/spec/support/vcr.rb +14 -0
- metadata +204 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
spec/avalara.yml
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2-p290@avalara
|
data/CHANGELOG
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
= 0.0.1 - February 3, 2012 - Initial Release with get_tax call
|
2
|
+
|
3
|
+
Not much in the way of features so far, but the rough draft of the get_tax call is in,
|
4
|
+
as well as error and warning message handling. Still need to update the docs with it
|
5
|
+
once an API to the gem is finalized.
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/intridea/hashie.git
|
3
|
+
revision: 6728ed259b4e8e679901b1d64e1d791f28ec186a
|
4
|
+
specs:
|
5
|
+
hashie (2.0.0.beta)
|
6
|
+
|
7
|
+
PATH
|
8
|
+
remote: .
|
9
|
+
specs:
|
10
|
+
avalara (0.0.1)
|
11
|
+
hashie
|
12
|
+
httparty
|
13
|
+
multi_json (~> 1.0.4)
|
14
|
+
|
15
|
+
GEM
|
16
|
+
remote: http://rubygems.org/
|
17
|
+
specs:
|
18
|
+
activesupport (3.2.1)
|
19
|
+
i18n (~> 0.6)
|
20
|
+
multi_json (~> 1.0)
|
21
|
+
addressable (2.2.6)
|
22
|
+
archive-tar-minitar (0.5.2)
|
23
|
+
columnize (0.3.6)
|
24
|
+
crack (0.3.1)
|
25
|
+
diff-lcs (1.1.3)
|
26
|
+
factory_girl (2.5.0)
|
27
|
+
activesupport
|
28
|
+
httparty (0.8.1)
|
29
|
+
multi_json
|
30
|
+
multi_xml
|
31
|
+
i18n (0.6.0)
|
32
|
+
linecache19 (0.5.12)
|
33
|
+
ruby_core_source (>= 0.1.4)
|
34
|
+
multi_json (1.0.4)
|
35
|
+
multi_xml (0.4.1)
|
36
|
+
rake (0.9.2.2)
|
37
|
+
rspec (2.8.0)
|
38
|
+
rspec-core (~> 2.8.0)
|
39
|
+
rspec-expectations (~> 2.8.0)
|
40
|
+
rspec-mocks (~> 2.8.0)
|
41
|
+
rspec-core (2.8.0)
|
42
|
+
rspec-expectations (2.8.0)
|
43
|
+
diff-lcs (~> 1.1.2)
|
44
|
+
rspec-mocks (2.8.0)
|
45
|
+
ruby-debug-base19 (0.11.25)
|
46
|
+
columnize (>= 0.3.1)
|
47
|
+
linecache19 (>= 0.5.11)
|
48
|
+
ruby_core_source (>= 0.1.4)
|
49
|
+
ruby-debug19 (0.11.6)
|
50
|
+
columnize (>= 0.3.1)
|
51
|
+
linecache19 (>= 0.5.11)
|
52
|
+
ruby-debug-base19 (>= 0.11.19)
|
53
|
+
ruby_core_source (0.1.5)
|
54
|
+
archive-tar-minitar (>= 0.5.2)
|
55
|
+
vcr (1.11.3)
|
56
|
+
webmock (1.7.10)
|
57
|
+
addressable (~> 2.2, > 2.2.5)
|
58
|
+
crack (>= 0.1.7)
|
59
|
+
|
60
|
+
PLATFORMS
|
61
|
+
ruby
|
62
|
+
|
63
|
+
DEPENDENCIES
|
64
|
+
avalara!
|
65
|
+
factory_girl
|
66
|
+
hashie!
|
67
|
+
rake
|
68
|
+
rspec
|
69
|
+
ruby-debug19
|
70
|
+
vcr
|
71
|
+
webmock
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Adam Fortuna
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
data/avalara.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'avalara/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'avalara'
|
7
|
+
s.version = Avalara::VERSION
|
8
|
+
s.authors = ['Adam Fortuna']
|
9
|
+
s.email = ['adam@envylabs.com']
|
10
|
+
s.homepage = 'https://github.com/adamfortuna/avalara'
|
11
|
+
s.summary = %q{A Ruby interface to the Avalara Tax API}
|
12
|
+
s.description = %q{This library provides Ruby calls to interact with the Avalara Tax API}
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.add_dependency 'hashie'
|
20
|
+
s.add_dependency 'httparty'
|
21
|
+
s.add_dependency 'multi_json', '~> 1.0.4'
|
22
|
+
|
23
|
+
s.add_development_dependency 'vcr'
|
24
|
+
s.add_development_dependency 'webmock'
|
25
|
+
s.add_development_dependency 'rspec'
|
26
|
+
s.add_development_dependency 'factory_girl'
|
27
|
+
s.add_development_dependency 'ruby-debug19'
|
28
|
+
end
|
data/lib/avalara.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'avalara/version'
|
4
|
+
require 'avalara/errors'
|
5
|
+
require 'avalara/configuration'
|
6
|
+
|
7
|
+
require 'avalara/api'
|
8
|
+
|
9
|
+
require 'avalara/types'
|
10
|
+
require 'avalara/request'
|
11
|
+
require 'avalara/response'
|
12
|
+
|
13
|
+
module Avalara
|
14
|
+
|
15
|
+
def self.configuration
|
16
|
+
@@_configuration ||= Avalara::Configuration.new
|
17
|
+
yield @@_configuration if block_given?
|
18
|
+
@@_configuration
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.configuration=(configuration)
|
22
|
+
raise ArgumentError, 'Expected a Avalara::Configuration instance' unless configuration.kind_of?(Configuration)
|
23
|
+
@@_configuration = configuration
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.configure(&block)
|
27
|
+
configuration(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.endpoint
|
31
|
+
configuration.endpoint
|
32
|
+
end
|
33
|
+
def self.endpoint=(endpoint)
|
34
|
+
configuration.endpoint = endpoint
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.username
|
38
|
+
configuration.username
|
39
|
+
end
|
40
|
+
def self.username=(username)
|
41
|
+
configuration.username = username
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.password
|
45
|
+
configuration.password
|
46
|
+
end
|
47
|
+
def self.password=(password)
|
48
|
+
configuration.password = password
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.version
|
52
|
+
configuration.version
|
53
|
+
end
|
54
|
+
def self.version=(version)
|
55
|
+
configuration.version = version
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.geographical_tax(latitude, longitude, sales_amount)
|
59
|
+
raise NotImplementedError
|
60
|
+
uri = [configuration.endpoint, configuration.version, "tax", "#{latitude},#{longitude}", "get"].join["/"]
|
61
|
+
|
62
|
+
response = API.get(uri,
|
63
|
+
:headers => API.headers_for('0'),
|
64
|
+
:query => { :saleamount => sales_amount }
|
65
|
+
)
|
66
|
+
rescue Timeout::Error
|
67
|
+
puts "Timed out"
|
68
|
+
raise TimeoutError
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.get_tax(invoice)
|
72
|
+
uri = [endpoint, version, 'tax', 'get'].join('/')
|
73
|
+
|
74
|
+
response = API.post(uri,
|
75
|
+
:body => invoice.to_json,
|
76
|
+
:headers => API.headers_for(invoice.to_json.length),
|
77
|
+
:basic_auth => authentication
|
78
|
+
)
|
79
|
+
|
80
|
+
return case response.code
|
81
|
+
when 200..299
|
82
|
+
Response::Invoice.new(response)
|
83
|
+
when 400..599
|
84
|
+
raise ApiError.new(Response::Invoice.new(response))
|
85
|
+
else
|
86
|
+
raise ApiError.new(response)
|
87
|
+
end
|
88
|
+
rescue Timeout::Error => e
|
89
|
+
raise TimeoutError.new(e)
|
90
|
+
rescue ApiError => e
|
91
|
+
raise e
|
92
|
+
rescue Exception => e
|
93
|
+
raise Error.new(e)
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def self.authentication
|
99
|
+
{ :username => username, :password => password}
|
100
|
+
end
|
101
|
+
end
|
data/lib/avalara/api.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'httparty'
|
3
|
+
require 'avalara/parser'
|
4
|
+
|
5
|
+
module Avalara
|
6
|
+
class API
|
7
|
+
include HTTParty
|
8
|
+
headers 'Accept' => 'application/json', 'Content-Type' => 'text/json'
|
9
|
+
format :json
|
10
|
+
parser Parser
|
11
|
+
|
12
|
+
def self.headers_for(length)
|
13
|
+
{ 'Date' => Time.now.httpdate(), 'User-Agent' => user_agent_string, "Content-Length" => length.to_s }
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def self.user_agent_string
|
19
|
+
"avalara/#{Avalara::VERSION} (Rubygems; Ruby #{RUBY_VERSION} #{RUBY_PLATFORM})"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class Avalara::Configuration
|
4
|
+
|
5
|
+
attr_writer :endpoint
|
6
|
+
attr_accessor :password
|
7
|
+
attr_accessor :username
|
8
|
+
attr_writer :version
|
9
|
+
|
10
|
+
##
|
11
|
+
# Public: Get the API endpoint used by the configuration. Unless explicitly
|
12
|
+
# set, the endpoint will default to the official production endpoint at
|
13
|
+
# 'https://avatax.avalara.net'.
|
14
|
+
#
|
15
|
+
# Returns the String for the API endpoint.
|
16
|
+
#
|
17
|
+
def endpoint
|
18
|
+
@endpoint ||= 'https://rest.avalara.net'
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Public: Get the API version. Defaults to 1.0.
|
23
|
+
#
|
24
|
+
# Returns the String for the API version.
|
25
|
+
#
|
26
|
+
def version
|
27
|
+
@version ||= '1.0'
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# To be removed when Crack is updated, see below.
|
4
|
+
require 'multi_json'
|
5
|
+
require 'httparty'
|
6
|
+
|
7
|
+
module Avalara
|
8
|
+
class Parser < ::HTTParty::Parser
|
9
|
+
SupportedFormats.merge!({'text/plain' => :json})
|
10
|
+
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
|
15
|
+
##
|
16
|
+
# Private: This was put in place entirely to appease Ruby 1.9.2-p290's more
|
17
|
+
# strict YAML parsing, which breaks Crack 0.1.8's JSON decoding.
|
18
|
+
#
|
19
|
+
# This will be removed when Crack supports decoding the API's returned
|
20
|
+
# values.
|
21
|
+
#
|
22
|
+
def json
|
23
|
+
decode_json(body)
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Private: This was put in place entirely to appease Ruby 1.9.2-p290's more
|
28
|
+
# strict YAML parsing, which breaks Crack 0.1.8's JSON decoding.
|
29
|
+
#
|
30
|
+
# This will be removed when Crack supports decoding the API's returned
|
31
|
+
# values.
|
32
|
+
#
|
33
|
+
def decode_json(body)
|
34
|
+
if body.to_s =~ /^(?:[\d]+|null|true|false)$/
|
35
|
+
MultiJson.decode("[#{body}]").first
|
36
|
+
else
|
37
|
+
MultiJson.decode body
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Avalara
|
4
|
+
module Request
|
5
|
+
autoload :Address, 'avalara/request/address'
|
6
|
+
autoload :DetailLevel, 'avalara/request/detail_level'
|
7
|
+
autoload :Invoice, 'avalara/request/invoice'
|
8
|
+
autoload :Line, 'avalara/request/line'
|
9
|
+
autoload :Message, 'avalara/request/message'
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Avalara
|
4
|
+
module Request
|
5
|
+
class Address < Avalara::Types::Stash
|
6
|
+
property :AddressCode, :from => :address_code, :required => true
|
7
|
+
property :Line1, :from => :line_1
|
8
|
+
property :Line2, :from => :line_2
|
9
|
+
property :Line3, :from => :line_3
|
10
|
+
property :City, :from => :city
|
11
|
+
property :Region, :from => :region
|
12
|
+
property :Country, :from => :country
|
13
|
+
property :PostalCode, :from => :postal_code
|
14
|
+
property :Latitude, :from => :latitude
|
15
|
+
property :Longitude, :from => :longitude
|
16
|
+
property :TaxRegionId, :from => :tax_region_id
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Avalara
|
4
|
+
module Request
|
5
|
+
class DetailLevel < Avalara::Types::Stash
|
6
|
+
property :Line, :from => :line
|
7
|
+
property :Summary, :from => :summary
|
8
|
+
property :Document, :from => :document
|
9
|
+
property :Tax, :from => :tax
|
10
|
+
property :Diagnostic, :from => :diagnostic
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
module Avalara
|
5
|
+
module Request
|
6
|
+
# Same as GetTaxRequest
|
7
|
+
class Invoice < Avalara::Types::Stash
|
8
|
+
coerce_key :DocDate, Avalara::Types::Date
|
9
|
+
|
10
|
+
# Set outgoing
|
11
|
+
property :CustomerCode, :from => :customer_code
|
12
|
+
property :DocDate, :from => :doc_date
|
13
|
+
property :CompanyCode, :from => :company_code
|
14
|
+
property :Commit, :from => :commit
|
15
|
+
property :CustomerUsageType, :from => :customer_usage_type
|
16
|
+
property :Discount, :from => :discount
|
17
|
+
property :DocCode, :from => :doc_code
|
18
|
+
property :PurchaseOrderNo, :from => :purchase_order_no
|
19
|
+
property :ExemptionNo, :from => :exemption_no
|
20
|
+
property :DetailLevel, :from => :detail_level
|
21
|
+
property :DocType, :from => :doc_type
|
22
|
+
property :PaymentDate, :from => :payment_date
|
23
|
+
property :Lines, :from => :lines
|
24
|
+
property :Addresses, :from => :addresses
|
25
|
+
property :ReferenceCode, :from => :reference_code
|
26
|
+
|
27
|
+
def addresses=(addresses)
|
28
|
+
self.Addresses = []
|
29
|
+
addresses.each do |address|
|
30
|
+
self.Addresses << Address.new(address)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def lines=(lines)
|
35
|
+
self.Lines = []
|
36
|
+
lines.each do |line|
|
37
|
+
self.Lines << Line.new(line)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_json
|
42
|
+
MultiJson.encode(self.to_hash, :pretty => true)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|