taxjar-ruby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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