suretax 0.2.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.example +4 -0
- data/.rubocop.yml +111 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +9 -9
- data/lib/suretax.rb +0 -1
- data/lib/suretax/api.rb +7 -7
- data/lib/suretax/api/cancel_request.rb +7 -7
- data/lib/suretax/api/group.rb +5 -6
- data/lib/suretax/api/item_message.rb +3 -3
- data/lib/suretax/api/request.rb +37 -37
- data/lib/suretax/api/request_item.rb +13 -17
- data/lib/suretax/api/response.rb +18 -19
- data/lib/suretax/api/tax.rb +11 -12
- data/lib/suretax/api/tax_amount.rb +3 -4
- data/lib/suretax/concerns.rb +1 -3
- data/lib/suretax/concerns/validatable.rb +21 -27
- data/lib/suretax/configuration.rb +17 -20
- data/lib/suretax/connection.rb +3 -5
- data/lib/suretax/constants/regulatory_codes.rb +8 -8
- data/lib/suretax/constants/response_groups.rb +6 -6
- data/lib/suretax/constants/sales_type_codes.rb +5 -5
- data/lib/suretax/constants/tax_situs_codes.rb +10 -10
- data/lib/suretax/constants/transaction_type_codes.rb +2 -2
- data/lib/suretax/response.rb +7 -10
- data/lib/suretax/version.rb +1 -1
- data/spec/lib/suretax/api/group_spec.rb +21 -22
- data/spec/lib/suretax/api/request_item_spec.rb +10 -12
- data/spec/lib/suretax/api/request_item_validations_spec.rb +73 -76
- data/spec/lib/suretax/api/request_spec.rb +62 -66
- data/spec/lib/suretax/api/request_validations_spec.rb +141 -143
- data/spec/lib/suretax/api/response_spec.rb +48 -52
- data/spec/lib/suretax/api/tax_amount_spec.rb +12 -12
- data/spec/lib/suretax/api/tax_spec.rb +26 -28
- data/spec/lib/suretax/configuration_spec.rb +21 -24
- data/spec/lib/suretax/connection_spec.rb +11 -15
- data/spec/lib/suretax/response_spec.rb +27 -31
- data/spec/spec_helper.rb +16 -17
- data/spec/support/cancellation_helper.rb +0 -1
- data/spec/support/connection_shared_examples.rb +8 -10
- data/spec/support/request_helper.rb +13 -14
- data/spec/support/suretax_helper.rb +2 -4
- data/spec/support/validations_shared_examples.rb +12 -12
- data/suretax.gemspec +10 -8
- metadata +7 -7
- data/.travis.yml +0 -13
data/lib/suretax/api/response.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(
|
1
|
+
require File.join(File.dirname(__FILE__), "item_message.rb")
|
2
2
|
|
3
3
|
module Suretax
|
4
4
|
module Api
|
@@ -8,12 +8,12 @@ module Suretax
|
|
8
8
|
|
9
9
|
def initialize(response_body)
|
10
10
|
@body = JSON.generate(response_body)
|
11
|
-
@status = response_body.fetch(
|
12
|
-
@transaction = response_body.fetch(
|
13
|
-
@message = response_body.fetch(
|
14
|
-
@success = response_body.fetch(
|
15
|
-
@client_tracking = response_body[
|
16
|
-
@total_tax = Amount.new(response_body[
|
11
|
+
@status = response_body.fetch("ResponseCode")
|
12
|
+
@transaction = response_body.fetch("TransId").to_s
|
13
|
+
@message = response_body.fetch("HeaderMessage")
|
14
|
+
@success = response_body.fetch("Successful") == "Y"
|
15
|
+
@client_tracking = response_body["ClientTracking"] || nil
|
16
|
+
@total_tax = Amount.new(response_body["TotalTax"])
|
17
17
|
|
18
18
|
build_groups(response_body)
|
19
19
|
build_item_messages(response_body)
|
@@ -24,26 +24,25 @@ module Suretax
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def item_errors?
|
27
|
-
@status ==
|
27
|
+
@status == "9001"
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
32
|
+
def build_groups(response_body)
|
33
|
+
@groups = []
|
34
|
+
if response_body["GroupList"].respond_to?(:map)
|
35
|
+
@groups = response_body.fetch("GroupList").map do |group|
|
36
|
+
Group.new(group)
|
38
37
|
end
|
39
38
|
end
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
41
|
+
def build_item_messages(response_body)
|
42
|
+
@item_messages = Array(response_body.fetch("ItemMessages", [])).map do |item_message|
|
43
|
+
ItemMessage.new(item_message)
|
45
44
|
end
|
45
|
+
end
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
data/lib/suretax/api/tax.rb
CHANGED
@@ -4,17 +4,17 @@ module Suretax
|
|
4
4
|
attr_reader :code, :description, :amount, :revenue, :county, :city, :rate, :taxable, :fee_rate, :tax_on_tax, :revenue_base
|
5
5
|
|
6
6
|
def initialize(response_params)
|
7
|
-
@code = response_params.fetch(
|
8
|
-
@description = response_params.fetch(
|
9
|
-
@amount = set_amount(response_params.fetch(
|
10
|
-
@revenue = response_params[
|
11
|
-
@county = response_params[
|
12
|
-
@city = response_params[
|
13
|
-
@rate = set_amount(response_params[
|
14
|
-
@taxable = set_amount(response_params[
|
15
|
-
@fee_rate = set_amount(response_params[
|
16
|
-
@tax_on_tax = set_amount(response_params[
|
17
|
-
@revenue_base = set_amount(response_params[
|
7
|
+
@code = response_params.fetch("TaxTypeCode")
|
8
|
+
@description = response_params.fetch("TaxTypeDesc")
|
9
|
+
@amount = set_amount(response_params.fetch("TaxAmount").to_f)
|
10
|
+
@revenue = response_params["Revenue"]
|
11
|
+
@county = response_params["CountyName"]
|
12
|
+
@city = response_params["CityName"]
|
13
|
+
@rate = set_amount(response_params["TaxRate"])
|
14
|
+
@taxable = set_amount(response_params["PercentTaxable"])
|
15
|
+
@fee_rate = set_amount(response_params["FeeRate"])
|
16
|
+
@tax_on_tax = set_amount(response_params["TaxOnTax"])
|
17
|
+
@revenue_base = set_amount(response_params["RevenueBase"])
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
@@ -22,7 +22,6 @@ module Suretax
|
|
22
22
|
def set_amount(value)
|
23
23
|
Amount.new(value) unless value.nil?
|
24
24
|
end
|
25
|
-
|
26
25
|
end
|
27
26
|
end
|
28
27
|
end
|
@@ -1,11 +1,11 @@
|
|
1
|
-
require
|
1
|
+
require "monetize"
|
2
2
|
|
3
3
|
module Suretax
|
4
4
|
module Api
|
5
5
|
class Amount
|
6
6
|
attr_reader :precision, :divisor
|
7
7
|
|
8
|
-
def initialize(amount, currency =
|
8
|
+
def initialize(amount, currency = "US6")
|
9
9
|
@amount = Monetize.parse(amount, currency)
|
10
10
|
@precision = count_significant_decimal_places
|
11
11
|
@divisor = @amount.currency.subunit_to_unit
|
@@ -24,7 +24,7 @@ module Suretax
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def cents
|
27
|
-
(("%.2f" % to_f).to_f * 100
|
27
|
+
(("%.2f" % to_f).to_f * 100).to_i
|
28
28
|
end
|
29
29
|
|
30
30
|
def params
|
@@ -40,7 +40,6 @@ module Suretax
|
|
40
40
|
def count_significant_decimal_places
|
41
41
|
@amount.currency.subunit_to_unit.to_s.scan(/0/).count
|
42
42
|
end
|
43
|
-
|
44
43
|
end
|
45
44
|
end
|
46
45
|
end
|
data/lib/suretax/concerns.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Suretax::Concerns
|
2
|
-
|
3
2
|
module Validatable
|
4
|
-
|
5
3
|
def self.included(base)
|
6
4
|
base.extend ClassMethods
|
7
5
|
base.send(:include, Validations)
|
@@ -11,18 +9,17 @@ module Suretax::Concerns
|
|
11
9
|
@errors = Errors.new
|
12
10
|
|
13
11
|
self.class.validatable_attributes.each do |attribute_name|
|
14
|
-
value =
|
15
|
-
assertion =
|
12
|
+
value = send(attribute_name)
|
13
|
+
assertion = send("valid_#{attribute_name}?", value)
|
16
14
|
|
17
15
|
@errors[attribute_name] = Error.new(attribute_name, value) unless assertion
|
18
16
|
end
|
19
17
|
|
20
18
|
@errors
|
21
19
|
end
|
22
|
-
|
20
|
+
alias validate! errors
|
23
21
|
|
24
22
|
class Error
|
25
|
-
|
26
23
|
attr_accessor :message, :value, :attribute
|
27
24
|
|
28
25
|
def initialize(attribute, value)
|
@@ -38,14 +35,14 @@ module Suretax::Concerns
|
|
38
35
|
end
|
39
36
|
|
40
37
|
def format_nested_errors(value)
|
41
|
-
value.map { |obj| obj.errors.messages.join(
|
38
|
+
value.map { |obj| obj.errors.messages.join(", ") }
|
42
39
|
end
|
43
40
|
|
44
41
|
def format_error(value)
|
45
42
|
if value.nil?
|
46
43
|
"nil"
|
47
44
|
elsif value.is_a?(String) && value.empty?
|
48
|
-
%
|
45
|
+
%('')
|
49
46
|
else
|
50
47
|
value
|
51
48
|
end
|
@@ -56,15 +53,13 @@ module Suretax::Concerns
|
|
56
53
|
end
|
57
54
|
end
|
58
55
|
|
59
|
-
class Errors < Hash
|
60
|
-
|
56
|
+
class Errors < Hash
|
61
57
|
def messages
|
62
|
-
|
58
|
+
map { |_key, value| value.message }
|
63
59
|
end
|
64
60
|
end
|
65
61
|
|
66
62
|
module ClassMethods
|
67
|
-
|
68
63
|
attr_writer :validatable_attributes
|
69
64
|
|
70
65
|
def validate(*attribute_names)
|
@@ -77,7 +72,6 @@ module Suretax::Concerns
|
|
77
72
|
end
|
78
73
|
|
79
74
|
module Validations
|
80
|
-
|
81
75
|
def valid_data_year?(value)
|
82
76
|
return false if blank?(value)
|
83
77
|
value.length == 4 &&
|
@@ -85,11 +79,11 @@ module Suretax::Concerns
|
|
85
79
|
end
|
86
80
|
|
87
81
|
def valid_data_month?(value)
|
88
|
-
matches?(value,month_list_subexpression)
|
82
|
+
matches?(value, month_list_subexpression)
|
89
83
|
end
|
90
84
|
|
91
85
|
def valid_items?(items)
|
92
|
-
|
86
|
+
items.none? { |item| item.errors.any? }
|
93
87
|
end
|
94
88
|
|
95
89
|
def valid_list?(value)
|
@@ -100,7 +94,7 @@ module Suretax::Concerns
|
|
100
94
|
return false if blank?(value)
|
101
95
|
numeric?(value) && value.length <= 10
|
102
96
|
end
|
103
|
-
|
97
|
+
alias valid_customer_number? valid_client_number?
|
104
98
|
|
105
99
|
def valid_business_unit?(value)
|
106
100
|
blank?(value) || (value.length <= 20 && alphanumeric?(value))
|
@@ -117,7 +111,7 @@ module Suretax::Concerns
|
|
117
111
|
end
|
118
112
|
|
119
113
|
def valid_return_file_code?(value)
|
120
|
-
matches?(value.to_s,
|
114
|
+
matches?(value.to_s, "[Q0]")
|
121
115
|
end
|
122
116
|
|
123
117
|
def valid_client_tracking?(value)
|
@@ -129,7 +123,7 @@ module Suretax::Concerns
|
|
129
123
|
end
|
130
124
|
|
131
125
|
def valid_response_type?(value)
|
132
|
-
matches?(value,
|
126
|
+
matches?(value, "[DS][1-9]")
|
133
127
|
end
|
134
128
|
|
135
129
|
def valid_line_number?(value)
|
@@ -160,14 +154,14 @@ module Suretax::Concerns
|
|
160
154
|
def valid_tax_exemption_code_list?(value)
|
161
155
|
valid_list?(value) && !blank?(value.first)
|
162
156
|
end
|
163
|
-
|
157
|
+
alias valid_tax_exemption_codes? valid_tax_exemption_code_list?
|
164
158
|
|
165
159
|
def optional_north_american_phone_number?(value)
|
166
160
|
blank?(value) || north_american_phone_number?(value)
|
167
161
|
end
|
168
|
-
|
169
|
-
|
170
|
-
|
162
|
+
alias valid_bill_to_number? optional_north_american_phone_number?
|
163
|
+
alias valid_orig_number? optional_north_american_phone_number?
|
164
|
+
alias valid_term_number? optional_north_american_phone_number?
|
171
165
|
|
172
166
|
private
|
173
167
|
|
@@ -184,24 +178,24 @@ module Suretax::Concerns
|
|
184
178
|
end
|
185
179
|
|
186
180
|
def numeric?(value)
|
187
|
-
matches?(value,'\d+')
|
181
|
+
matches?(value, '\d+')
|
188
182
|
end
|
189
183
|
|
190
184
|
def alphanumeric?(value)
|
191
|
-
matches?(value,
|
185
|
+
matches?(value, "[a-z0-9]+")
|
192
186
|
end
|
193
187
|
|
194
188
|
def blank?(value)
|
195
|
-
value.nil? || matches?(value,'\s*')
|
189
|
+
value.nil? || matches?(value, '\s*')
|
196
190
|
end
|
197
191
|
|
198
|
-
def matches?(value,subexpression)
|
192
|
+
def matches?(value, subexpression)
|
199
193
|
/\A#{subexpression}\z/i === value
|
200
194
|
end
|
201
195
|
|
202
196
|
# Month numbers 1-12 with optional leading zero
|
203
197
|
def month_list_subexpression
|
204
|
-
"0?(?:" + (1..12).to_a.join(
|
198
|
+
"0?(?:" + (1..12).to_a.join("|") + ")"
|
205
199
|
end
|
206
200
|
end
|
207
201
|
end
|
@@ -4,8 +4,8 @@ module Suretax
|
|
4
4
|
class Configuration
|
5
5
|
include Singleton
|
6
6
|
|
7
|
-
REQUEST_VERSIONS = [1, 2, 3, 4]
|
8
|
-
CANCEL_VERSIONS = [1]
|
7
|
+
REQUEST_VERSIONS = [1, 2, 3, 4].freeze
|
8
|
+
CANCEL_VERSIONS = [1].freeze
|
9
9
|
|
10
10
|
attr_accessor :validation_key, :base_url, :client_number,
|
11
11
|
:request_version, :cancel_version, :logger
|
@@ -43,18 +43,18 @@ module Suretax
|
|
43
43
|
|
44
44
|
def request_path
|
45
45
|
@request_path ||=
|
46
|
-
|
46
|
+
"/Services/V%02d/SureTax.asmx/PostRequest" % request_version
|
47
47
|
end
|
48
48
|
|
49
49
|
def cancel_path
|
50
50
|
@cancel_path ||=
|
51
|
-
|
51
|
+
"/Services/V%02d/SureTax.asmx/CancelPostRequest" % cancel_version
|
52
52
|
end
|
53
53
|
|
54
54
|
private
|
55
55
|
|
56
56
|
def test_host
|
57
|
-
|
57
|
+
"https://testapi.taxrating.net"
|
58
58
|
end
|
59
59
|
|
60
60
|
def register_currencies
|
@@ -63,22 +63,19 @@ module Suretax
|
|
63
63
|
|
64
64
|
def register_dollar_with_six_decimal_places
|
65
65
|
Money::Currency.register(
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
symbolize_names: true
|
79
|
-
}
|
66
|
+
priority: 1,
|
67
|
+
iso_code: "US6",
|
68
|
+
iso_numeric: "840",
|
69
|
+
name: "Dollar with six decimal places",
|
70
|
+
symbol: "$",
|
71
|
+
subunit: "Cent",
|
72
|
+
subunit_to_unit: 1_000_000,
|
73
|
+
symbol_first: true,
|
74
|
+
html_entity: "$",
|
75
|
+
decimal_mark: ".",
|
76
|
+
thousands_separator: ",",
|
77
|
+
symbolize_names: true
|
80
78
|
)
|
81
79
|
end
|
82
|
-
|
83
80
|
end
|
84
81
|
end
|
data/lib/suretax/connection.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "uri"
|
2
|
+
require "json"
|
3
3
|
|
4
4
|
module Suretax
|
5
|
-
|
6
5
|
class Connection
|
7
6
|
attr_accessor :headers
|
8
7
|
|
9
8
|
def initialize(args = {})
|
10
9
|
@link = Excon.new(args[:base_url] || api_host)
|
11
|
-
@headers = {
|
10
|
+
@headers = { "Content-Type" => "application/x-www-form-urlencoded" }
|
12
11
|
end
|
13
12
|
|
14
13
|
def post(body = {})
|
@@ -46,5 +45,4 @@ module Suretax
|
|
46
45
|
Suretax.configuration
|
47
46
|
end
|
48
47
|
end
|
49
|
-
|
50
48
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module Suretax
|
2
2
|
REGULATORY_CODES = {
|
3
|
-
ilec:
|
4
|
-
ixc:
|
5
|
-
clec:
|
6
|
-
voip:
|
7
|
-
isp:
|
8
|
-
wireless:
|
9
|
-
default:
|
10
|
-
}
|
3
|
+
ilec: "00",
|
4
|
+
ixc: "01",
|
5
|
+
clec: "02",
|
6
|
+
voip: "03",
|
7
|
+
isp: "04",
|
8
|
+
wireless: "05",
|
9
|
+
default: "99"
|
10
|
+
}.freeze
|
11
11
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Suretax
|
2
|
-
RESPONSE_GROUPS = {
|
3
|
-
by_state:
|
4
|
-
by_state_and_invoice:
|
5
|
-
by_state_and_customer:
|
6
|
-
by_state_and_customer_and_invoice:
|
7
|
-
}
|
2
|
+
RESPONSE_GROUPS = {
|
3
|
+
by_state: "00",
|
4
|
+
by_state_and_invoice: "01",
|
5
|
+
by_state_and_customer: "02",
|
6
|
+
by_state_and_customer_and_invoice: "03"
|
7
|
+
}.freeze
|
8
8
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Suretax
|
2
|
-
TAX_SITUS_RULES =
|
3
|
-
two_of_three:
|
4
|
-
billed_to_number:
|
5
|
-
origination_number:
|
6
|
-
billing_zip:
|
7
|
-
billing_zip_plus_4:
|
8
|
-
private_lines:
|
9
|
-
point_to_point:
|
10
|
-
vat:
|
11
|
-
}
|
2
|
+
TAX_SITUS_RULES = {
|
3
|
+
two_of_three: "01",
|
4
|
+
billed_to_number: "02",
|
5
|
+
origination_number: "03",
|
6
|
+
billing_zip: "04",
|
7
|
+
billing_zip_plus_4: "05",
|
8
|
+
private_lines: "06",
|
9
|
+
point_to_point: "07",
|
10
|
+
vat: "14"
|
11
|
+
}.freeze
|
12
12
|
end
|