vat-gst-calculator 0.5.0 → 0.7.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/README.md +3 -1
- data/lib/easyship/sales_tax/calculator/formula.rb +98 -51
- data/lib/easyship/sales_tax/calculator/version.rb +1 -1
- data/lib/easyship/sales_tax/calculator.rb +27 -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: 4c0b1547695777a69f063993628affe4eaf28498180236ca0bd2e5902d5bd7d7
|
4
|
+
data.tar.gz: 5f7fd7051a155b3f5c0187ec2ebde52df83991a35491e0d8abf780d93ff94aed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 444a34ccad4d894adca304083e25cc4baae48ae6a6abb7d1aabcd0c074a87d790120f0c6abd6ff2bfa242174c9939a00957c53a399151d68fe1acc0a551d7fbb
|
7
|
+
data.tar.gz: a7b0bcf732ca7a34da47c703e6b9f85fdae33461ad2602c73058f5770284b0e50204a3938b6674fd30a46317ab5481971a2d5d282665fccc70e713f1c9c8a28c
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -26,7 +26,9 @@ Easyship::SalesTax::Calculator.calculate(
|
|
26
26
|
destination_country_alpha2: destination_country_alpha2,
|
27
27
|
origin_state: origin_state,
|
28
28
|
destination_state: destination_state,
|
29
|
-
fees: Easyship::SalesTax::Fee.new(10, 20, 30, 40) # (shipment_charge_total, insurance_fee, pickup_fee, residential_surcharge)
|
29
|
+
fees: Easyship::SalesTax::Fee.new(10, 20, 30, 40), # (shipment_charge_total, insurance_fee, pickup_fee, residential_surcharge)
|
30
|
+
effective_timestamp: "2023-01-01", # String and Time instances are supported. Default to current time (utc)
|
31
|
+
effective_country_alpha2s: ["HK", "US"] # when empty or not specified, all avalilable country data is used
|
30
32
|
)
|
31
33
|
```
|
32
34
|
|
@@ -1,7 +1,19 @@
|
|
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
|
+
|
15
|
+
DEFAULT_EFFECTIVE_TIMESTAMP = Time.at(0).utc.freeze
|
16
|
+
|
5
17
|
class << self
|
6
18
|
def build_fee_struct(shipment_charge_total, insurance_fee, pickup_fee, residential_surcharge)
|
7
19
|
{
|
@@ -12,23 +24,42 @@ module Easyship
|
|
12
24
|
}
|
13
25
|
end
|
14
26
|
|
15
|
-
def
|
16
|
-
|
27
|
+
def effective_data(country_alpha2, effective_timestamp = nil, effective_country_alpha2s = [])
|
28
|
+
DOMESTIC
|
29
|
+
.slice(*(effective_country_alpha2s.empty? ? DEFAULT_EFFECTIVE_COUNTRY_ALPHA2S : effective_country_alpha2s))
|
30
|
+
.fetch(country_alpha2, [])
|
31
|
+
.find { |rates| rates[:effective_timestamp] <= effective_time(effective_timestamp) }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def effective_time(effective_timestamp)
|
37
|
+
case effective_timestamp
|
38
|
+
when String
|
39
|
+
Time.parse(effective_timestamp).utc
|
40
|
+
when Time
|
41
|
+
effective_timestamp
|
42
|
+
else
|
43
|
+
Time.now.utc
|
44
|
+
end
|
17
45
|
end
|
18
46
|
end
|
19
47
|
|
20
48
|
DOMESTIC = {
|
21
|
-
'AU' => {
|
49
|
+
'AU' => [{
|
50
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
22
51
|
sales_tax_website_name: 'GST',
|
23
|
-
sales_tax: {
|
24
|
-
provincial_sales_taxes: {
|
25
|
-
},
|
26
|
-
'GB' => {
|
52
|
+
sales_tax: {'_ALL': build_fee_struct(0.1, 0, 0.1, 0)},
|
53
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
54
|
+
}],
|
55
|
+
'GB' => [{
|
56
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
27
57
|
sales_tax_website_name: 'VAT',
|
28
|
-
sales_tax: {
|
29
|
-
provincial_sales_taxes: {
|
30
|
-
},
|
31
|
-
'CA' => {
|
58
|
+
sales_tax: {'_ALL': build_fee_struct(0.2, 0, 0.2, 0.2)}, # TBC
|
59
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
60
|
+
}],
|
61
|
+
'CA' => [{
|
62
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
32
63
|
sales_tax_website_name: 'Taxes',
|
33
64
|
sales_tax: {
|
34
65
|
'AB' => build_fee_struct(0.05, 0, 0.05, 0.05), # Alberta
|
@@ -46,41 +77,52 @@ module Easyship
|
|
46
77
|
'YT' => build_fee_struct(0.05, 0, 0.05, 0.05), # Yukon
|
47
78
|
},
|
48
79
|
provincial_sales_taxes: {
|
49
|
-
'AB' =>
|
50
|
-
'BC' =>
|
51
|
-
'MB' =>
|
52
|
-
'NB' =>
|
53
|
-
'NL' =>
|
54
|
-
'NT' =>
|
55
|
-
'NS' =>
|
56
|
-
'NU' =>
|
57
|
-
'ON' =>
|
58
|
-
'PE' =>
|
80
|
+
'AB' => NO_TAX, # Alberta
|
81
|
+
'BC' => NO_TAX, # British Columbia
|
82
|
+
'MB' => NO_TAX, # Manitoba
|
83
|
+
'NB' => NO_TAX, # New Brunswick
|
84
|
+
'NL' => NO_TAX, # Newfoundland and Labrador
|
85
|
+
'NT' => NO_TAX, # Northwest Territories
|
86
|
+
'NS' => NO_TAX, # Nova Scotia
|
87
|
+
'NU' => NO_TAX, # Nunavut
|
88
|
+
'ON' => NO_TAX, # Ontario
|
89
|
+
'PE' => NO_TAX, # Prince Edward Island
|
59
90
|
'QC' => build_fee_struct(0.09975, 0, 0.09975, 0.09975), # Quebec
|
60
|
-
'SK' =>
|
61
|
-
'YT' =>
|
91
|
+
'SK' => NO_TAX, # Saskatchewan
|
92
|
+
'YT' => NO_TAX, # Yukon
|
62
93
|
}
|
63
|
-
},
|
64
|
-
'SG' =>
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
94
|
+
}],
|
95
|
+
'SG' => [
|
96
|
+
{
|
97
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
98
|
+
sales_tax_website_name: 'GST',
|
99
|
+
sales_tax: {'_ALL': build_fee_struct(0.07, 0.07, 0.07, 0.07)},
|
100
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
101
|
+
},
|
102
|
+
{
|
103
|
+
effective_timestamp: Time.utc(2023, 1, 1, 8),
|
104
|
+
sales_tax_website_name: 'GST',
|
105
|
+
sales_tax: {'_ALL': build_fee_struct(0.08, 0.08, 0.08, 0.08)},
|
106
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
107
|
+
}
|
108
|
+
],
|
109
|
+
'HK' => [{
|
110
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
70
111
|
sales_tax_website_name: nil,
|
71
|
-
sales_tax: {
|
72
|
-
provincial_sales_taxes: {
|
73
|
-
},
|
112
|
+
sales_tax: {'_ALL': NO_TAX},
|
113
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
114
|
+
}],
|
74
115
|
# 'NL' => {
|
75
116
|
# sales_tax_website_name: 'VAT',
|
76
117
|
# sales_tax: { '_ALL': build_fee_struct(0.21, 0, 0.21, 0.21) },
|
77
118
|
# provincial_sales_taxes: { '_ALL': no_taxes }
|
78
119
|
# },
|
79
|
-
'US' => {
|
120
|
+
'US' => [{
|
121
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
80
122
|
sales_tax_website_name: nil,
|
81
|
-
sales_tax: {
|
82
|
-
provincial_sales_taxes: {
|
83
|
-
},
|
123
|
+
sales_tax: {'_ALL': NO_TAX},
|
124
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
125
|
+
}],
|
84
126
|
# 'DE' => {
|
85
127
|
# sales_tax_website_name: 'VAT',
|
86
128
|
# sales_tax: { '_ALL': build_fee_struct(0.19, 0, 0, 0) },
|
@@ -126,16 +168,18 @@ module Easyship
|
|
126
168
|
# sales_tax: { '_ALL': build_fee_struct(0.2, 0, 0, 0) },
|
127
169
|
# provincial_sales_taxes: { '_ALL': no_taxes }
|
128
170
|
# },
|
129
|
-
'AE' => {
|
171
|
+
'AE' => [{
|
172
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
130
173
|
sales_tax_website_name: 'VAT',
|
131
|
-
sales_tax: {
|
132
|
-
provincial_sales_taxes: {
|
133
|
-
},
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
174
|
+
sales_tax: {'_ALL': build_fee_struct(0.05, 0, 0, 0)},
|
175
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
176
|
+
}],
|
177
|
+
'IE' => [{
|
178
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
179
|
+
sales_tax_website_name: 'VAT',
|
180
|
+
sales_tax: { '_ALL': build_fee_struct(0.23, 0, 0.23, 0.23) },
|
181
|
+
provincial_sales_taxes: { '_ALL': NO_TAX }
|
182
|
+
}],
|
139
183
|
# 'DK' => {
|
140
184
|
# sales_tax_website_name: 'VAT',
|
141
185
|
# sales_tax: { '_ALL': build_fee_struct(0.25, 0, 0, 0) },
|
@@ -176,11 +220,12 @@ module Easyship
|
|
176
220
|
# sales_tax: { '_ALL': build_fee_struct(0.1, 0, 0, 0) },
|
177
221
|
# provincial_sales_taxes: { '_ALL': no_taxes }
|
178
222
|
# },
|
179
|
-
'NZ' => {
|
223
|
+
'NZ' => [{
|
224
|
+
effective_timestamp: DEFAULT_EFFECTIVE_TIMESTAMP,
|
180
225
|
sales_tax_website_name: 'VAT',
|
181
|
-
sales_tax: {
|
182
|
-
provincial_sales_taxes: {
|
183
|
-
},
|
226
|
+
sales_tax: {'_ALL': build_fee_struct(0.15, 0.15, 0.15, 0.15)},
|
227
|
+
provincial_sales_taxes: {'_ALL': NO_TAX}
|
228
|
+
}],
|
184
229
|
# 'IN' => {
|
185
230
|
# sales_tax_website_name: 'VAT',
|
186
231
|
# sales_tax: { '_ALL': build_fee_struct(0.15, 0, 0, 0) },
|
@@ -196,7 +241,9 @@ module Easyship
|
|
196
241
|
# sales_tax: { '_ALL': build_fee_struct(0.16, 0, 0, 0) },
|
197
242
|
# provincial_sales_taxes: { '_ALL': no_taxes }
|
198
243
|
# }
|
199
|
-
}.freeze
|
244
|
+
}.transform_values { |value| value.sort_by { |rates| -rates[:effective_timestamp].to_i } }.freeze
|
245
|
+
|
246
|
+
DEFAULT_EFFECTIVE_COUNTRY_ALPHA2S = DOMESTIC.keys.freeze
|
200
247
|
end
|
201
248
|
end
|
202
249
|
end
|
@@ -6,33 +6,45 @@ 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, effective_country_alpha2s: [])
|
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(
|
16
|
+
domestic_value(
|
17
|
+
origin_country_alpha2: origin_country_alpha2,
|
18
|
+
origin_state: origin_state,
|
19
|
+
destination_state: destination_state,
|
20
|
+
fees: fees,
|
21
|
+
effective_timestamp: effective_timestamp,
|
22
|
+
effective_country_alpha2s: effective_country_alpha2s
|
23
|
+
)
|
15
24
|
else
|
16
|
-
|
25
|
+
FALLBACK_VALUE
|
17
26
|
end
|
18
27
|
rescue
|
19
|
-
|
28
|
+
FALLBACK_VALUE
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.sales_tax_website_name(country_alpha2, effective_timestamp = nil)
|
32
|
+
rates = Formula.effective_data(country_alpha2, effective_timestamp)
|
33
|
+
(rates || {}).dig(:sales_tax_website_name)
|
20
34
|
end
|
21
35
|
|
22
|
-
|
23
|
-
|
24
|
-
|
36
|
+
private
|
37
|
+
|
38
|
+
def self.domestic_value(origin_country_alpha2: nil, origin_state: nil, destination_state: nil, fees: nil, effective_timestamp: nil, effective_country_alpha2s: [])
|
39
|
+
rates = Formula.effective_data(origin_country_alpha2, effective_timestamp, effective_country_alpha2s)
|
40
|
+
return FALLBACK_VALUE if rates.nil?
|
25
41
|
|
26
42
|
{
|
27
|
-
sales_tax: tax_calculate(
|
28
|
-
provincial_sales_tax: tax_calculate(
|
43
|
+
sales_tax: tax_calculate(rates[:sales_tax], nil, destination_state, fees, false),
|
44
|
+
provincial_sales_tax: tax_calculate(rates[:provincial_sales_taxes], origin_state, destination_state, fees, true)
|
29
45
|
}
|
30
46
|
end
|
31
47
|
|
32
|
-
def self.fallback_value
|
33
|
-
{ sales_tax: 0, provincial_sales_tax: 0 }
|
34
|
-
end
|
35
|
-
|
36
48
|
def self.tax_calculate(formula, origin_state, destination_state, fees, is_provincial_sales_taxes)
|
37
49
|
if (tax_destination_formula = formula[destination_state.to_s.upcase])
|
38
50
|
# ONLY CA has provincial_sales_taxes(QST/PST) and it only apply when ship within same state
|
@@ -46,11 +58,6 @@ module Easyship
|
|
46
58
|
end
|
47
59
|
end
|
48
60
|
|
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
61
|
def self.in_eu?(country_alpha2)
|
55
62
|
%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
63
|
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.7.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:
|
12
|
+
date: 2023-01-31 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
|