sales_tax 0.1.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: 5011f177f821f6b3468d1ecab3d8829cabc7ddae
4
+ data.tar.gz: 381b02e2d0ce3bcd8412b631906313e4b232f382
5
+ SHA512:
6
+ metadata.gz: 6ddf68e4a9f6e088f178e61364bb08d4893b026fab4a66203fc48affc7f3e65d3354824899f49f53ef691463d624ca6b7cb836af0b06c3fe0f972043bd4e9432
7
+ data.tar.gz: 9d085887bc28ee666dad29f9dee04af40ef0357de1277e44fb8683f9bc40228d3ea80ab20f7f92ae065ed01b01e8443625c838c54540a9ec9d7707c862b11ac4
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ data/*.csv
3
+ pkg
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.0
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - '2.3.0'
6
+
7
+ script: bundle exec rspec
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sales_tax (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.2.5)
10
+ rake (10.4.2)
11
+ rspec (3.4.0)
12
+ rspec-core (~> 3.4.0)
13
+ rspec-expectations (~> 3.4.0)
14
+ rspec-mocks (~> 3.4.0)
15
+ rspec-core (3.4.1)
16
+ rspec-support (~> 3.4.0)
17
+ rspec-expectations (3.4.0)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.4.0)
20
+ rspec-mocks (3.4.1)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.4.0)
23
+ rspec-support (3.4.1)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 1.10)
30
+ rake (~> 10.4.2)
31
+ rspec (~> 3.4.0)
32
+ sales_tax!
33
+
34
+ BUNDLED WITH
35
+ 1.11.2
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2016 Dirk Gadsden
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # sales_tax
2
+
3
+ Interface to the public [Avalara TaxRates](http://www.taxrates.com/) database for sales taxes in the United States of America. Easily look up combined, state, and county rates by zip code.
4
+
5
+ **Notice**: This is a development tool only; it is not intended for use as tax compliance software and should not be relied upon for financial decisions. As detailed in the [LICENSE](LICENSE), **use of this software is at your own risk**. The author(s) disclaim all warranties and by your use of this software you agree to waive the author(s) of any and all liabilities. You should consult with a tax professional before collecting or paying taxes.
6
+
7
+ [![Build Status](https://travis-ci.org/dirk/sales_tax.svg)](https://travis-ci.org/dirk/sales_tax)
8
+
9
+ ## Installation
10
+
11
+ Install via Rubygems or add the dependency via Bundler:
12
+
13
+ ```sh
14
+ # Rubygems directly
15
+ gem install sales_tax
16
+
17
+ # In your Gemfile
18
+ gem 'sales_tax'
19
+ ```
20
+
21
+ After installation you will need to download the publicly available CSV data from Avalara's [taxrates.com](http://www.taxrates.com/download-tax-tables/):
22
+
23
+ ```sh
24
+ # Ensure the gem is loaded when `rake` is called (this is done automatically
25
+ # if you're using Rails and the gem is in your Gemfile)
26
+ bundle exec rake sales_tax:download
27
+ ```
28
+
29
+ ## Basic usage
30
+
31
+ You can look up the tax rates via zip code:
32
+
33
+ ```ruby
34
+ SalesTax['94107']
35
+ # => <struct SalesTax::Rate region_name="SAN FRANCISCO COUNTY",
36
+ # region_code="AIUQ",
37
+ # combined_rate=0.0875,
38
+ # state_rate=0.065,
39
+ # county_rate=0.01,
40
+ # city_rate=0.0,
41
+ # special_rate=0.0125>
42
+ ```
43
+
44
+ ## License
45
+
46
+ Licensed under the MIT license. See [LICENSE](LICENSE) for details.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'sales_tax'
@@ -0,0 +1,55 @@
1
+ # This is a list of public CSV URLs from:
2
+ # http://www.taxrates.com/download-tax-tables/
3
+
4
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_AL201602.csv
5
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_AK201602.csv
6
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_AZ201602.csv
7
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_AR201602.csv
8
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_CA201602.csv
9
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_CO201602.csv
10
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_CT201602.csv
11
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_DE201602.csv
12
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_FL201602.csv
13
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_GA201602.csv
14
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_HI201602.csv
15
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_ID201602.csv
16
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_IL201602.csv
17
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_WV201602.csv
18
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_VA201602.csv
19
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_TX201602.csv
20
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_SC201602.csv
21
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_PA201602.csv
22
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_OH201602.csv
23
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_NY201602.csv
24
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_NH201602.csv
25
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_MT201602.csv
26
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_MN201602.csv
27
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_MD201602.csv
28
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_KY201602.csv
29
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_IN201602.csv
30
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_IA201602.csv
31
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_LA201602.csv
32
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_MA201602.csv
33
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_MS201602.csv
34
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_NE201602.csv
35
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_NJ201602.csv
36
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_NC201602.csv
37
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_OK201602.csv
38
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_PR201602.csv
39
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_SD201602.csv
40
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_UT201602.csv
41
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_WA201602.csv
42
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_WI201602.csv
43
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_WY201602.csv
44
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_DC201602.csv
45
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_VT201602.csv
46
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_TN201602.csv
47
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_RI201602.csv
48
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_OR201602.csv
49
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_ND201602.csv
50
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_NM201602.csv
51
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_NV201602.csv
52
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_MO201602.csv
53
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_MI201602.csv
54
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_ME201602.csv
55
+ http://taxrates.csv.s3.amazonaws.com/TAXRATES_ZIP5_KS201602.csv
@@ -0,0 +1,16 @@
1
+ module SalesTax
2
+ def self.auto_load
3
+ data_path = File.join Dir.getwd, 'data'
4
+ data_files = Dir.glob(File.join data_path, '*.csv')
5
+
6
+ if data_files.empty?
7
+ raise "No data files found in #{data_path}"
8
+ end
9
+
10
+ data_files.each do |path|
11
+ SalesTax::Data.load_csv_file path
12
+ end
13
+ end
14
+ end
15
+
16
+ SalesTax.auto_load
@@ -0,0 +1,9 @@
1
+ require 'sales_tax/rate_store'
2
+
3
+ module SalesTax
4
+ Data = RateStore.new
5
+
6
+ def self.[](zip_code)
7
+ Data.find_by_zip_code zip_code
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ require 'csv'
2
+
3
+ module SalesTax
4
+ Rate = Struct.new(:region_name, :region_code, :combined_rate, :state_rate, :county_rate, :city_rate, :special_rate)
5
+
6
+ class RateStore
7
+ def initialize
8
+ # Map of 5-digit US zip code to `Rate` instances
9
+ @data = {}
10
+ end
11
+
12
+ def empty?
13
+ @data.empty?
14
+ end
15
+
16
+ def find_by_zip_code(zip_code)
17
+ @data[zip_code.to_s]
18
+ end
19
+
20
+ FIELDS_MAP = [
21
+ ['TaxRegionName' , :to_s],
22
+ ['TaxRegionCode' , :to_s],
23
+ ['CombinedRate' , :to_f],
24
+ ['StateRate' , :to_f],
25
+ ['CountyRate' , :to_f],
26
+ ['CityRate' , :to_f],
27
+ ['SpecialRate' , :to_f],
28
+ ]
29
+
30
+ def load_csv_file(path)
31
+ CSV.foreach(path, headers: :first_row) do |row|
32
+ zip_code = row['ZipCode']
33
+
34
+ fields = FIELDS_MAP.map do |(row_key, transform)|
35
+ row[row_key].send transform
36
+ end
37
+
38
+ @data[zip_code] = Rate.new *fields
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,28 @@
1
+ require 'open-uri'
2
+
3
+ namespace 'sales_tax' do
4
+
5
+ desc 'Download CSVs'
6
+ task 'download' do
7
+ list_file_path = File.expand_path '../../../../data/taxrates_download_list.txt', __FILE__
8
+
9
+ list_file = File.read list_file_path
10
+
11
+ list = list_file
12
+ .split("\n")
13
+ .map(&:strip)
14
+ .reject {|line| line.start_with?('#') || line.empty? }
15
+
16
+ output_base_path = File.join Dir.getwd, 'data'
17
+
18
+ list.each do |url|
19
+ print "Downloading #{url} ..."
20
+
21
+ output_path = File.join output_base_path, File.basename(url)
22
+ File.write output_path, open(url).read
23
+
24
+ print " Done\n"
25
+ end
26
+ end
27
+
28
+ end # namespace sales_tax
@@ -0,0 +1,3 @@
1
+ module SalesTax
2
+ VERSION = '0.1.0'
3
+ end
data/lib/sales_tax.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'sales_tax/version'
2
+ require 'sales_tax/base'
3
+ require 'sales_tax/auto_load'
4
+
5
+ if defined? Rake
6
+ load File.join(File.dirname(__FILE__), 'sales_tax', 'tasks', 'download.rake')
7
+ end
data/sales_tax.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'sales_tax/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'sales_tax'
7
+ s.version = SalesTax::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Dirk Gadsden']
10
+ s.email = ['dirk@esherido.com']
11
+ s.homepage = 'https://github.com/dirk/sales_tax'
12
+ s.summary = 'Look up sales tax rates by zip code.'
13
+ s.description = s.summary
14
+ s.license = 'MIT'
15
+
16
+ s.files = `git ls-files`.split "\n"
17
+ s.test_files = `git ls-files -- {test}/*`.split "\n"
18
+ s.require_paths = ['lib']
19
+
20
+ # s.add_dependency 'ffi', '~> 1.9.10'
21
+
22
+ s.add_development_dependency 'bundler', '~> 1.10'
23
+ s.add_development_dependency 'rake', '~> 10.4.2'
24
+ s.add_development_dependency 'rspec', '~> 3.4.0'
25
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe SalesTax do
4
+ let(:mock_row) {
5
+ {
6
+ 'State' => 'AA',
7
+ 'ZipCode' => '12345',
8
+ 'TaxRegionName' => 'A SUNNY SOCIALIST WORLD',
9
+ 'TaxRegionCode' => 'ABCD',
10
+ 'CombinedRate' => '0.03',
11
+ 'StateRate' => '0.02',
12
+ 'CountyRate' => '0.01',
13
+ 'CityRate' => '0',
14
+ 'SpecialRate' => '0',
15
+ }
16
+ }
17
+
18
+ it 'auto-loads CSV data' do
19
+ allow(CSV).to receive(:foreach).and_yield(mock_row)
20
+ allow(Dir).to receive(:glob).and_return(['a/b.csv'])
21
+
22
+ require 'sales_tax/auto_load'
23
+
24
+ expect(SalesTax::Data).not_to be_empty
25
+
26
+ row = SalesTax::Data.find_by_zip_code '12345'
27
+
28
+ expect(row).not_to be_nil
29
+ expect(row.region_code).to eq 'ABCD'
30
+ expect(row.combined_rate).to eq 0.03
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe SalesTax::RateStore do
4
+ before(:each) do
5
+ @rate_store = SalesTax::RateStore.new
6
+
7
+ @rate_store.instance_eval do
8
+ fake_rate = SalesTax::Rate.new(
9
+ region_name: 'A SUNNY SOCIALIST WORLD',
10
+ region_code: 'ABCD',
11
+ combined_rate: 0.03,
12
+ state_rate: 0.02,
13
+ county_rate: 0.01,
14
+ city_rate: 0.0,
15
+ special_rate: 0.0,
16
+ )
17
+
18
+ @data = {
19
+ '12345' => fake_rate
20
+ }
21
+ end
22
+ end
23
+
24
+ describe '#find_by_zip_code' do
25
+ it 'finds a rate by zip code' do
26
+ expect(@rate_store.find_by_zip_code '12345').not_to be_nil
27
+ end
28
+
29
+ it 'returns nil if rate not found' do
30
+ expect(@rate_store.find_by_zip_code 'bad-zip').to be_nil
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'sales_tax/base'
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sales_tax
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dirk Gadsden
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 10.4.2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 10.4.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.4.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.4.0
55
+ description: Look up sales tax rates by zip code.
56
+ email:
57
+ - dirk@esherido.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".ruby-version"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - Gemfile.lock
68
+ - LICENSE
69
+ - README.md
70
+ - Rakefile
71
+ - data/taxrates_download_list.txt
72
+ - lib/sales_tax.rb
73
+ - lib/sales_tax/auto_load.rb
74
+ - lib/sales_tax/base.rb
75
+ - lib/sales_tax/rate_store.rb
76
+ - lib/sales_tax/tasks/download.rake
77
+ - lib/sales_tax/version.rb
78
+ - sales_tax.gemspec
79
+ - spec/auto_load_spec.rb
80
+ - spec/rate_store_spec.rb
81
+ - spec/spec_helper.rb
82
+ homepage: https://github.com/dirk/sales_tax
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.5.1
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Look up sales tax rates by zip code.
106
+ test_files: []
107
+ has_rdoc: