taxjar-ruby 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2a129c647b66e1054f0438dcd65485090e28b533
4
+ data.tar.gz: d5a63ab29627fb0c98deab4e59007712f934d726
5
+ SHA512:
6
+ metadata.gz: 9e2f7ec935c28f4262da4555e1419d399ddf720d5a39f0f12dc370b3f78e0b3f452396ab555e0f5a69476c909af7b98154bd29d61a48b21c6f89e858c5e7b744
7
+ data.tar.gz: 5a13e3b0650ecc020f1d028d37aca79dd89af0ae16bad544ac9e3e12a01cbc578d1dbb90b3e6143d59732c3be44a964cc9afbdc108164b80352cecc122d83f58
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.swp
16
+ *.swo
17
+ vendor/bundle
18
+ tester.rb
19
+ tags
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --order random
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'yard'
4
+
5
+ group :test do
6
+ gem 'rspec', '~>3'
7
+ gem 'webmock', '~>1'
8
+
9
+ end
10
+ # Specify your gem's dependencies in taxjar-ruby.gemspec
11
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Tim Case
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # The Taxjar Ruby Gem
2
+ [![Taxjar](http://www.taxjar.com/img/TJ_logo_color_office_png.png)](http://developers.taxjar.com)
3
+
4
+ A Ruby interface to the Taxjar API. TaxJar makes sales tax filing easier for online sellers and merchants.
5
+ See local jurisdictional tax reports, get payment reminders, and more. You can use our API to access TaxJar API endpoints,
6
+ which can get information on sales tax rates, categories or upload transactions.
7
+
8
+ * This wrapper supports 100% of the [Taxjar API Version 2](http://developers.taxjar.com/api/#introduction)
9
+ * Data returned from API calls are mapped into Ruby objects
10
+
11
+
12
+ ## Gem Dependencies
13
+ Installing this gem also installs the following gems:
14
+
15
+ * [http](https://github.com/httprb/http.rb) http.rb: a fast Ruby HTTP client with a chainable API and full streaming support
16
+ * [addressable](https://github.com/sporkmonger/addressable) Addressable is a replacement for the URI implementation that is part of Ruby's standard library. It more closely conforms to the relevant RFCs and adds support for IRIs and URI templates.
17
+ * [memoizable](https://github.com/dkubb/memoizable) Memoize method return values
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+ ```ruby
23
+ gem 'taxjar-ruby', require: 'taxjar'
24
+ ```
25
+ And then execute:
26
+ ```shell
27
+ $ bundle install
28
+ ```
29
+ Or install it yourself as:
30
+ ```shell
31
+ $ gem install taxjar-ruby
32
+ ```
33
+ ## Quick Start Guide
34
+
35
+ First, [get an api key from Taxar][https://app.taxjar.com/api_sign_up/plus/].
36
+
37
+ Then copy and paste in your API keys:
38
+
39
+ ```ruby
40
+ client = Taxjar::Client.new(api_key: "YOUR KEY")
41
+ ```
42
+
43
+
44
+ You are ready to use Taxjar.
45
+
46
+ ## Usage
47
+
48
+ ### List all tax categories
49
+ ```ruby
50
+ categories = client.categories
51
+
52
+ ```
53
+ ### List tax rates for a location (by zip/postal code)
54
+ ```ruby
55
+ rates = client.rates_for_location('10001')
56
+ ```
57
+
58
+ ### Calculate Sales tax for an order
59
+ ```ruby
60
+ order = client.tax_for_order({
61
+ :to_country => 'US',
62
+ :to_zip => '90002',
63
+ :to_city => 'Los Angeles',
64
+ :from_country => 'US',
65
+ :from_zip => '92093',
66
+ :from_city => 'San Diego',
67
+ :amount => 16.50,
68
+ :shipping => 1.5,
69
+ :line_items => [{:quantity => 1,
70
+ :product_identifier => '12-34243-9',
71
+ :unit_price => 15.0,
72
+ :product_tax_code => 31000}]
73
+ })
74
+ ```
75
+
76
+ ### Create order transaction
77
+ ```ruby
78
+ order = client.create_order({
79
+ :transaction_id => '123',
80
+ :transaction_date => '2015/05/14',
81
+ :to_country => 'US',
82
+ :to_zip => '90002',
83
+ :to_city => 'Los Angeles',
84
+ :to_street => '123 Palm Grove Ln',
85
+ :amount => 17.45,
86
+ :shipping => 1.5,
87
+ :sales_tax => 0.95,
88
+ :line_items => [{:quantity => 1,
89
+ :product_identifier => '12-34243-9',
90
+ :descriptiion => 'Fuzzy Widget',
91
+ :unit_price => 15.0,
92
+ :sales_tax => 0.95}]
93
+ })
94
+ ```
95
+
96
+ ### Update order transaction
97
+ ```ruby
98
+ order = client.update_order({
99
+ :transaction_id => '123',
100
+ :amount => 17.95,
101
+ :shipping => 2.0,
102
+ :line_items => [{:quantity => 1,
103
+ :product_identifier => '12-34243-0',
104
+ :descriptiion => 'Heavy Widget',
105
+ :unit_price => 15.0,
106
+ :discount => 0.0,
107
+ :sales_tax => 0.95}]
108
+ })
109
+ ```
110
+
111
+ ### Create refund transaction
112
+ ```ruby
113
+ refund = client.create_refund({
114
+ :transaction_id => '321',
115
+ :transaction_date => '2015/05/14',
116
+ :transaction_reference_id => '123',
117
+ :to_country => 'US',
118
+ :to_zip => '90002',
119
+ :to_state => 'CA',
120
+ :to_city => 'Los Angeles',
121
+ :to_street => '123 Palm Grove Ln',
122
+ :amount => 17.45,
123
+ :shipping => 1.5,
124
+ :sales_tax => 0.95,
125
+ :line_items => [{:quantity => 1,
126
+ :product_identifier => '12-34243-9',
127
+ :descriptiion => 'Fuzzy Widget',
128
+ :unit_price => 15.0,
129
+ :sales_tax => 0.95}]
130
+ })
131
+ ```
132
+
133
+ ### Update refund transaction
134
+ ```ruby
135
+ refund = client.update_refund{
136
+ :transaction_id => '321',
137
+ :amount => 17.95,
138
+ :shipping => 2.0,
139
+ :sales_tax => 0.95,
140
+ :line_items => [{:quantity => 1,
141
+ :product_identifier => '12-34243-9',
142
+ :descriptiion => 'Heavy Widget',
143
+ :unit_price => 15.0,
144
+ :sales_tax => 0.95}]
145
+ })
146
+ ```
147
+ ## Tests
148
+ An Rspec test suite is available to ensure API functionality:
149
+
150
+ 1. $ git clone git://github.com/taxjar/taxjar-ruby.git
151
+ 2. $ bundle install (installs rspec and other supporting gems, see
152
+ [GEMFILE](https://github.com/taxjar/taxjar-ruby/blob/master/Gemfile)
153
+ for complete listing)
154
+ 3. $ rspec
155
+
156
+ ## More Information
157
+ More information can be found on the [Taxjar developer site](https://developers.taxjar.com).
158
+
159
+ ## License
160
+ Taxjar is released under the [MIT
161
+ License](https://github.com/taxjar/taxjar-ruby/blob/master/LICENSE.txt).
162
+
163
+ ## Support
164
+ Bug reports and feature requests should be filed on the [github issue
165
+ tracking page](https://github.com/taxjar/taxjar-ruby/issues).
166
+
167
+ ## Contributing
168
+
169
+ 1. Fork it
170
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
171
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
172
+ 4. Push to the branch (`git push origin my-new-feature`)
173
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/lib/taxjar.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "taxjar/base"
2
+ require "taxjar/breakdown"
3
+ require "taxjar/breakdown_line_item"
4
+ require "taxjar/category"
5
+ require "taxjar/client"
6
+ require "taxjar/line_item"
7
+ require "taxjar/order"
8
+ require "taxjar/rate"
9
+ require "taxjar/refund"
10
+ require "taxjar/shipping"
11
+ require "taxjar/tax"
12
+ require "taxjar/version"
13
+
14
+ module Taxjar
15
+ end
@@ -0,0 +1,37 @@
1
+ require 'taxjar/api/utils'
2
+ module Taxjar
3
+ module API
4
+ include Taxjar::API::Utils
5
+
6
+ def categories(options = {})
7
+ perform_get_with_objects("/v2/categories", 'categories', options, Taxjar::Category)
8
+ end
9
+
10
+ def rates_for_location(postal_code, options ={})
11
+ perform_get_with_object("/v2/rates/#{postal_code}", 'rate', options, Taxjar::Rate)
12
+ end
13
+
14
+ def tax_for_order(options = {})
15
+ perform_post_with_object("/v2/taxes", 'tax', options, Taxjar::Tax)
16
+ end
17
+
18
+ def create_order(options = {})
19
+ perform_post_with_object("/v2/transactions/orders", 'order', options, Taxjar::Order)
20
+ end
21
+
22
+ def update_order(options = {})
23
+ id = options.fetch(:transaction_id)
24
+ perform_put_with_object("/v2/transactions/orders/#{id}", 'order', options, Taxjar::Order)
25
+ end
26
+
27
+ def create_refund(options = {})
28
+ perform_post_with_object("/v2/transactions/refunds", 'refund', options, Taxjar::Refund)
29
+ end
30
+
31
+ def update_refund(options = {})
32
+ id = options.fetch(:transaction_id)
33
+ perform_put_with_object("/v2/transactions/refunds/#{id}", 'refund', options, Taxjar::Refund)
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,70 @@
1
+ require 'addressable/uri'
2
+ require 'http'
3
+
4
+ module Taxjar
5
+ module API
6
+ class Request
7
+ BASE_URL = 'https://api.taxjar.com'
8
+
9
+ attr_reader :client, :uri, :headers, :request_method, :path, :object_key, :options
10
+
11
+ # @param client [Taxjar::Client]
12
+ # @param request_method [String, Symbol]
13
+ # @param path [String]
14
+ # @param object_key [String]
15
+ def initialize(client, request_method, path, object_key, options = {})
16
+ @client = client
17
+ @request_method = request_method
18
+ @path = path
19
+ @uri = Addressable::URI.parse(BASE_URL + path)
20
+ set_request_headers
21
+ @object_key = object_key
22
+ @options = options
23
+ end
24
+
25
+ def perform
26
+ options_key = @request_method == :get ? :params : :json
27
+ response = HTTP.with(headers).public_send(request_method, uri.to_s, options_key => @options)
28
+ response_body = symbolize_keys!(response.parse)
29
+ fail_or_return_response_body(response.code, response_body)
30
+ end
31
+
32
+ private
33
+
34
+
35
+ def set_request_headers
36
+ @headers = {}
37
+ @headers[:user_agent] = client.user_agent
38
+ @headers[:authorization] = "Bearer #{client.api_key}"
39
+ end
40
+
41
+ def symbolize_keys!(object)
42
+ if object.is_a?(Array)
43
+ object.each_with_index do |val, index|
44
+ object[index] = symbolize_keys!(val)
45
+ end
46
+ elsif object.is_a?(Hash)
47
+ object.keys.each do |key|
48
+ object[key.to_sym] = symbolize_keys!(object.delete(key))
49
+ end
50
+ end
51
+ object
52
+ end
53
+
54
+ def fail_or_return_response_body(code, body)
55
+ e = extract_error(code, body)
56
+ fail(e) if e
57
+ body[object_key.to_sym]
58
+ end
59
+
60
+ def extract_error(code, body)
61
+ klass = Taxjar::Error::ERRORS[code]
62
+ if !klass.nil?
63
+ klass.from_response(body)
64
+ end
65
+ end
66
+
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,40 @@
1
+ require 'taxjar/api/request'
2
+
3
+ module Taxjar
4
+ module API
5
+ module Utils
6
+
7
+ def perform_request(request_method, path, object_key, options = {})
8
+ Taxjar::API::Request.new(self, request_method, path, object_key, options).perform
9
+ end
10
+
11
+ def perform_get_with_object(path, object_key, options, klass)
12
+ perform_request_with_object(:get, path, object_key, options, klass)
13
+ end
14
+
15
+ def perform_get_with_objects(path, object_key, options, klass)
16
+ perform_request_with_objects(:get, path, object_key, options, klass)
17
+ end
18
+
19
+ def perform_post_with_object(path, object_key, options, klass)
20
+ perform_request_with_object(:post, path, object_key, options, klass)
21
+ end
22
+
23
+ def perform_put_with_object(path, object_key, options, klass)
24
+ perform_request_with_object(:put, path, object_key, options, klass)
25
+ end
26
+
27
+ def perform_request_with_object(request_method, path, object_key, options, klass)
28
+ response = perform_request(request_method, path, object_key, options)
29
+ klass.new(response)
30
+ end
31
+
32
+ def perform_request_with_objects(request_method, path, object_key, options, klass)
33
+ response_array = perform_request(request_method, path, object_key, options) || []
34
+ response_array.collect do |element|
35
+ klass.new(element)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,88 @@
1
+ require 'addressable/uri'
2
+ require 'forwardable'
3
+ require 'memoizable'
4
+
5
+ module Taxjar
6
+ class Base
7
+ extend Forwardable
8
+ include Memoizable
9
+
10
+ attr_reader :attrs
11
+ alias_method :to_h, :attrs
12
+ alias_method :to_hash, :to_h
13
+
14
+ def map_collection(klass, key)
15
+ Array(@attrs[key.to_sym]).map do |entity|
16
+ klass.new(entity)
17
+ end
18
+ end
19
+
20
+ class << self
21
+
22
+ def attr_reader(*attrs)
23
+ attrs.each do |attr|
24
+ define_attribute_method(attr)
25
+ define_predicate_method(attr)
26
+ end
27
+ end
28
+
29
+ def object_attr_reader(klass, key1, key2 = nil)
30
+ define_attribute_method(key1, klass, key2)
31
+ define_predicate_method(key1)
32
+ end
33
+
34
+ def define_attribute_method(key1, klass = nil, key2 = nil)
35
+ define_method(key1) do
36
+ if attr_falsey_or_empty?(key1)
37
+ else
38
+ klass.nil? ? @attrs[key1] : klass.new(attrs_for_object(key1, key2))
39
+ end
40
+ end
41
+ memoize(key1)
42
+ end
43
+
44
+ def define_predicate_method(key1, key2 = key1)
45
+ define_method(:"#{key1}?") do
46
+ !attr_falsey_or_empty?(key2)
47
+ end
48
+ memoize(:"#{key1}?")
49
+ end
50
+ end
51
+
52
+ def initialize(attrs = {})
53
+ attrs = values_as_floats_where_possible(attrs)
54
+ @attrs = attrs || {}
55
+ end
56
+
57
+ def [](method)
58
+ warn "#{Kernel.caller.first}: [DEPRECATION] #[#{method.inspect}] is deprecated. Use ##{method} to fetch the value."
59
+ send(method.to_sym)
60
+ rescue NoMethodError
61
+ nil
62
+ end
63
+
64
+ private
65
+
66
+ def attr_falsey_or_empty?(key)
67
+ !@attrs[key] || @attrs[key].respond_to?(:empty?) && @attrs[key].empty?
68
+ end
69
+
70
+ def attrs_for_object(key1, key2 = nil)
71
+ if key2.nil?
72
+ @attrs[key1]
73
+ else
74
+ attrs = @attrs.dup
75
+ attrs.delete(key1).merge(key2 => attrs)
76
+ end
77
+ end
78
+
79
+ def values_as_floats_where_possible(attrs)
80
+ attrs.map{|k, v| [k, to_f_or_i_or_s(v)]}.to_h
81
+ end
82
+
83
+ def to_f_or_i_or_s(v)
84
+ ((float = Float(v)) && (float % 1.0 == 0) ? float.to_i : float) rescue v
85
+ end
86
+
87
+ end
88
+ end