vat-gst-calculator 0.4.9 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/lib/easyship/sales_tax/calculator/formula.rb +89 -47
- data/lib/easyship/sales_tax/calculator/version.rb +1 -1
- data/lib/easyship/sales_tax/calculator.rb +20 -20
- data/vat-gst-calculator.gemspec +0 -2
- metadata +2 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f39992ff401d87c4d256cbbe7da9ef39e03e134b9e21ca5f4ba258d9ad613497
|
4
|
+
data.tar.gz: 118ee1b247f9536cdaf16aad6246ba8d61d48ee817a02ba7510c1245ccf4d52d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ba20e1380d4264138c446a675d5e1a6b5147e39713dcf7d441b706d09295214a0661f75e47411136f459dbf38843a38443d400d98cfc29e3d748e39ef426199
|
7
|
+
data.tar.gz: 490338962e3e8146c6a851aaa4c027a491cc6bb9f276206a00d8687af5b80ab2e7891565d3308086cbd099e5cd71913441124e5590e851519622f211824f531b
|
data/.gitignore
CHANGED
@@ -1,7 +1,18 @@
|
|
1
|
+
require "time"
|
2
|
+
|
1
3
|
module Easyship
|
2
4
|
module SalesTax
|
3
5
|
module Formula
|
4
6
|
class Error < StandardError; end
|
7
|
+
|
8
|
+
NO_TAX = {
|
9
|
+
shipment_charge_total: 0,
|
10
|
+
insurance_fee: 0,
|
11
|
+
pickup_fee: 0,
|
12
|
+
residential_surcharge: 0
|
13
|
+
}.freeze
|
14
|
+
DEFAULT_EFFECTIVE_TIMESTAMP = Time.at(0).utc.freeze
|
15
|
+
|
5
16
|
class << self
|
6
17
|
def build_fee_struct(shipment_charge_total, insurance_fee, pickup_fee, residential_surcharge)
|
7
18
|
{
|
@@ -12,23 +23,41 @@ module Easyship
|
|
12
23
|
}
|
13
24
|
end
|
14
25
|
|
15
|
-
def
|
16
|
-
|
26
|
+
def effective_data(country_alpha2, effective_timestamp = nil)
|
27
|
+
data = DOMESTIC.fetch(country_alpha2, [])
|
28
|
+
|
29
|
+
data.find { |rates| rates[:effective_timestamp] <= effective_time(effective_timestamp) }
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def effective_time(effective_timestamp)
|
35
|
+
case effective_timestamp
|
36
|
+
when String
|
37
|
+
Time.parse(effective_timestamp).utc
|
38
|
+
when Time
|
39
|
+
effective_timestamp
|
40
|
+
else
|
41
|
+
Time.now.utc
|
42
|
+
end
|
17
43
|
end
|
18
44
|
end
|
19
45
|
|
20
46
|
DOMESTIC = {
|
21
|
-
'AU' => {
|
47
|
+
'AU' => [{
|
48
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
22
49
|
sales_tax_website_name: 'GST',
|
23
|
-
sales_tax: {
|
24
|
-
provincial_sales_taxes: {
|
25
|
-
},
|
26
|
-
'GB' => {
|
50
|
+
sales_tax: {'_ALL': build_fee_struct(0.1, 0, 0.1, 0)},
|
51
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
52
|
+
}],
|
53
|
+
'GB' => [{
|
54
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
27
55
|
sales_tax_website_name: 'VAT',
|
28
|
-
sales_tax: {
|
29
|
-
provincial_sales_taxes: {
|
30
|
-
},
|
31
|
-
'CA' => {
|
56
|
+
sales_tax: {'_ALL': build_fee_struct(0.2, 0, 0.2, 0.2)}, # TBC
|
57
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
58
|
+
}],
|
59
|
+
'CA' => [{
|
60
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
32
61
|
sales_tax_website_name: 'Taxes',
|
33
62
|
sales_tax: {
|
34
63
|
'AB' => build_fee_struct(0.05, 0, 0.05, 0.05), # Alberta
|
@@ -46,41 +75,52 @@ module Easyship
|
|
46
75
|
'YT' => build_fee_struct(0.05, 0, 0.05, 0.05), # Yukon
|
47
76
|
},
|
48
77
|
provincial_sales_taxes: {
|
49
|
-
'AB' =>
|
50
|
-
'BC' =>
|
51
|
-
'MB' =>
|
52
|
-
'NB' =>
|
53
|
-
'NL' =>
|
54
|
-
'NT' =>
|
55
|
-
'NS' =>
|
56
|
-
'NU' =>
|
57
|
-
'ON' =>
|
58
|
-
'PE' =>
|
78
|
+
'AB' => NO_TAX, # Alberta
|
79
|
+
'BC' => NO_TAX, # British Columbia
|
80
|
+
'MB' => NO_TAX, # Manitoba
|
81
|
+
'NB' => NO_TAX, # New Brunswick
|
82
|
+
'NL' => NO_TAX, # Newfoundland and Labrador
|
83
|
+
'NT' => NO_TAX, # Northwest Territories
|
84
|
+
'NS' => NO_TAX, # Nova Scotia
|
85
|
+
'NU' => NO_TAX, # Nunavut
|
86
|
+
'ON' => NO_TAX, # Ontario
|
87
|
+
'PE' => NO_TAX, # Prince Edward Island
|
59
88
|
'QC' => build_fee_struct(0.09975, 0, 0.09975, 0.09975), # Quebec
|
60
|
-
'SK' =>
|
61
|
-
'YT' =>
|
89
|
+
'SK' => NO_TAX, # Saskatchewan
|
90
|
+
'YT' => NO_TAX, # Yukon
|
62
91
|
}
|
63
|
-
},
|
64
|
-
'SG' =>
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
92
|
+
}],
|
93
|
+
'SG' => [
|
94
|
+
{
|
95
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
96
|
+
sales_tax_website_name: 'GST',
|
97
|
+
sales_tax: {'_ALL': build_fee_struct(0.07, 0.07, 0.07, 0.07)},
|
98
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
99
|
+
},
|
100
|
+
{
|
101
|
+
effective_timestamp: Time.utc(2023, 1, 1, 8),
|
102
|
+
sales_tax_website_name: 'GST',
|
103
|
+
sales_tax: {'_ALL': build_fee_struct(0.08, 0.08, 0.08, 0.08)},
|
104
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
105
|
+
}
|
106
|
+
],
|
107
|
+
'HK' => [{
|
108
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
70
109
|
sales_tax_website_name: nil,
|
71
|
-
sales_tax: {
|
72
|
-
provincial_sales_taxes: {
|
73
|
-
},
|
110
|
+
sales_tax: {'_ALL': NO_TAX},
|
111
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
112
|
+
}],
|
74
113
|
# 'NL' => {
|
75
114
|
# sales_tax_website_name: 'VAT',
|
76
115
|
# sales_tax: { '_ALL': build_fee_struct(0.21, 0, 0.21, 0.21) },
|
77
116
|
# provincial_sales_taxes: { '_ALL': no_taxes }
|
78
117
|
# },
|
79
|
-
'US' => {
|
118
|
+
'US' => [{
|
119
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
80
120
|
sales_tax_website_name: nil,
|
81
|
-
sales_tax: {
|
82
|
-
provincial_sales_taxes: {
|
83
|
-
},
|
121
|
+
sales_tax: {'_ALL': NO_TAX},
|
122
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
123
|
+
}],
|
84
124
|
# 'DE' => {
|
85
125
|
# sales_tax_website_name: 'VAT',
|
86
126
|
# sales_tax: { '_ALL': build_fee_struct(0.19, 0, 0, 0) },
|
@@ -126,11 +166,12 @@ module Easyship
|
|
126
166
|
# sales_tax: { '_ALL': build_fee_struct(0.2, 0, 0, 0) },
|
127
167
|
# provincial_sales_taxes: { '_ALL': no_taxes }
|
128
168
|
# },
|
129
|
-
'AE' => {
|
169
|
+
'AE' => [{
|
170
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
130
171
|
sales_tax_website_name: 'VAT',
|
131
|
-
sales_tax: {
|
132
|
-
provincial_sales_taxes: {
|
133
|
-
},
|
172
|
+
sales_tax: {'_ALL': build_fee_struct(0.05, 0, 0, 0)},
|
173
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
174
|
+
}],
|
134
175
|
# 'IE' => {
|
135
176
|
# sales_tax_website_name: 'VAT',
|
136
177
|
# sales_tax: { '_ALL': build_fee_struct(0.23, 0, 0, 0) },
|
@@ -176,11 +217,12 @@ module Easyship
|
|
176
217
|
# sales_tax: { '_ALL': build_fee_struct(0.1, 0, 0, 0) },
|
177
218
|
# provincial_sales_taxes: { '_ALL': no_taxes }
|
178
219
|
# },
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
220
|
+
'NZ' => [{
|
221
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
222
|
+
sales_tax_website_name: 'VAT',
|
223
|
+
sales_tax: {'_ALL': build_fee_struct(0.15, 0.15, 0.15, 0.15)},
|
224
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
225
|
+
}],
|
184
226
|
# 'IN' => {
|
185
227
|
# sales_tax_website_name: 'VAT',
|
186
228
|
# sales_tax: { '_ALL': build_fee_struct(0.15, 0, 0, 0) },
|
@@ -196,7 +238,7 @@ module Easyship
|
|
196
238
|
# sales_tax: { '_ALL': build_fee_struct(0.16, 0, 0, 0) },
|
197
239
|
# provincial_sales_taxes: { '_ALL': no_taxes }
|
198
240
|
# }
|
199
|
-
}.freeze
|
241
|
+
}.transform_values { |value| value.sort_by { |rates| -rates[:effective_timestamp].to_i } }.freeze
|
200
242
|
end
|
201
243
|
end
|
202
244
|
end
|
@@ -6,33 +6,38 @@ module Easyship
|
|
6
6
|
module Calculator
|
7
7
|
class Error < StandardError; end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
FALLBACK_VALUE = {sales_tax: 0, provincial_sales_tax: 0}.freeze
|
10
|
+
|
11
|
+
def self.calculate(origin_country_alpha2: nil, destination_country_alpha2: nil, origin_state: nil, destination_state: nil, fees: nil, effective_timestamp: nil)
|
12
|
+
return FALLBACK_VALUE if origin_country_alpha2.nil? || origin_country_alpha2.empty? || destination_country_alpha2.nil? || destination_country_alpha2.empty?
|
13
|
+
return FALLBACK_VALUE unless fees.is_a?(Fee)
|
12
14
|
|
13
15
|
if domestic?(origin_country_alpha2, destination_country_alpha2) || within_eu?(origin_country_alpha2, destination_country_alpha2)
|
14
|
-
domestic_value(origin_country_alpha2: origin_country_alpha2, origin_state: origin_state, destination_state: destination_state, fees: fees)
|
16
|
+
domestic_value(origin_country_alpha2: origin_country_alpha2, origin_state: origin_state, destination_state: destination_state, fees: fees, effective_timestamp: effective_timestamp)
|
15
17
|
else
|
16
|
-
|
18
|
+
FALLBACK_VALUE
|
17
19
|
end
|
18
20
|
rescue
|
19
|
-
|
21
|
+
FALLBACK_VALUE
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.sales_tax_website_name(country_alpha2, effective_timestamp = nil)
|
25
|
+
rates = Formula.effective_data(country_alpha2, effective_timestamp)
|
26
|
+
(rates || {}).dig(:sales_tax_website_name)
|
20
27
|
end
|
21
28
|
|
22
|
-
|
23
|
-
|
24
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
def self.domestic_value(origin_country_alpha2: nil, origin_state: nil, destination_state: nil, fees: nil, effective_timestamp: nil)
|
32
|
+
rates = Formula.effective_data(origin_country_alpha2, effective_timestamp)
|
33
|
+
return FALLBACK_VALUE if rates.nil?
|
25
34
|
|
26
35
|
{
|
27
|
-
sales_tax: tax_calculate(
|
28
|
-
provincial_sales_tax: tax_calculate(
|
36
|
+
sales_tax: tax_calculate(rates[:sales_tax], nil, destination_state, fees, false),
|
37
|
+
provincial_sales_tax: tax_calculate(rates[:provincial_sales_taxes], origin_state, destination_state, fees, true)
|
29
38
|
}
|
30
39
|
end
|
31
40
|
|
32
|
-
def self.fallback_value
|
33
|
-
{ sales_tax: 0, provincial_sales_tax: 0 }
|
34
|
-
end
|
35
|
-
|
36
41
|
def self.tax_calculate(formula, origin_state, destination_state, fees, is_provincial_sales_taxes)
|
37
42
|
if (tax_destination_formula = formula[destination_state.to_s.upcase])
|
38
43
|
# ONLY CA has provincial_sales_taxes(QST/PST) and it only apply when ship within same state
|
@@ -46,11 +51,6 @@ module Easyship
|
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
49
|
-
def self.sales_tax_website_name(country_alpha2)
|
50
|
-
return if Formula::DOMESTIC[country_alpha2.to_s].nil? || Formula::DOMESTIC[country_alpha2.to_s].empty?
|
51
|
-
Formula::DOMESTIC[country_alpha2][:sales_tax_website_name]
|
52
|
-
end
|
53
|
-
|
54
54
|
def self.in_eu?(country_alpha2)
|
55
55
|
%w(NL LU EE LT HU BE PT SK HR CZ IT FI PL MT DE SI RO BG AT SE CY DK FR IE ES GR LV).include?(country_alpha2)
|
56
56
|
end
|
data/vat-gst-calculator.gemspec
CHANGED
@@ -23,8 +23,6 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
|
-
spec.add_development_dependency "bundler", "~> 1.17"
|
27
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
28
26
|
spec.add_development_dependency "rspec", "~> 3.0"
|
29
27
|
spec.add_development_dependency "byebug"
|
30
28
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vat-gst-calculator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aloha Chen
|
@@ -9,36 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-12-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: bundler
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - "~>"
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: '1.17'
|
21
|
-
type: :development
|
22
|
-
prerelease: false
|
23
|
-
version_requirements: !ruby/object:Gem::Requirement
|
24
|
-
requirements:
|
25
|
-
- - "~>"
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
version: '1.17'
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: rake
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - "~>"
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: '10.0'
|
35
|
-
type: :development
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - "~>"
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: '10.0'
|
42
14
|
- !ruby/object:Gem::Dependency
|
43
15
|
name: rspec
|
44
16
|
requirement: !ruby/object:Gem::Requirement
|