vizjerai-avalara 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +25 -0
  3. data/CHANGELOG.md +14 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README +5 -0
  7. data/Rakefile +10 -0
  8. data/lib/avalara/api.rb +26 -0
  9. data/lib/avalara/configuration.rb +31 -0
  10. data/lib/avalara/errors.rb +8 -0
  11. data/lib/avalara/request/address.rb +15 -0
  12. data/lib/avalara/request/cancel_tax.rb +18 -0
  13. data/lib/avalara/request/detail_level.rb +13 -0
  14. data/lib/avalara/request/invoice.rb +40 -0
  15. data/lib/avalara/request/invoice_address.rb +19 -0
  16. data/lib/avalara/request/line.rb +24 -0
  17. data/lib/avalara/request.rb +13 -0
  18. data/lib/avalara/response/address_validation.rb +24 -0
  19. data/lib/avalara/response/cancel_tax.rb +20 -0
  20. data/lib/avalara/response/cancel_tax_result.rb +20 -0
  21. data/lib/avalara/response/invoice.rb +38 -0
  22. data/lib/avalara/response/message.rb +13 -0
  23. data/lib/avalara/response/tax.rb +24 -0
  24. data/lib/avalara/response/tax_address.rb +16 -0
  25. data/lib/avalara/response/tax_detail.rb +16 -0
  26. data/lib/avalara/response/tax_line.rb +22 -0
  27. data/lib/avalara/response/validation_address.rb +46 -0
  28. data/lib/avalara/response.rb +16 -0
  29. data/lib/avalara/types/date.rb +10 -0
  30. data/lib/avalara/types/stash.rb +28 -0
  31. data/lib/avalara/types.rb +8 -0
  32. data/lib/avalara/version.rb +5 -0
  33. data/lib/avalara.rb +121 -0
  34. data/spec/avalara.yml.example +3 -0
  35. data/spec/factories/addresses.rb +11 -0
  36. data/spec/factories/cancel_taxs.rb +9 -0
  37. data/spec/factories/detail_levels.rb +9 -0
  38. data/spec/factories/invoice_addresses.rb +15 -0
  39. data/spec/factories/invoices.rb +18 -0
  40. data/spec/factories/lines.rb +16 -0
  41. data/spec/fixtures/net/Avalara/_cancel_tax/successful_response.yml +59 -0
  42. data/spec/fixtures/net/Avalara/_cancel_tax/with_missing_doc_code/unsuccessful_response.yml +75 -0
  43. data/spec/fixtures/net/Avalara/_geographical_tax/successful_response.yml +92 -0
  44. data/spec/fixtures/net/Avalara/_geographical_tax/with_incomplete_address/unsuccessful_response.yml +66 -0
  45. data/spec/fixtures/net/Avalara/_get_tax/successful_response.yml +151 -0
  46. data/spec/fixtures/net/Avalara/_get_tax/with_missing_required_field/unsuccessful_response.yml +73 -0
  47. data/spec/fixtures/net/Avalara/_validate_address/successful_response.yml +76 -0
  48. data/spec/fixtures/net/Avalara/_validate_address/with_missing_postal_code/unsuccessful_response.yml +68 -0
  49. data/spec/models/avalara/configuration_spec.rb +55 -0
  50. data/spec/models/avalara/request/address_spec.rb +20 -0
  51. data/spec/models/avalara/request/detail_level_spec.rb +18 -0
  52. data/spec/models/avalara/request/invoice_address_spec.rb +24 -0
  53. data/spec/models/avalara/request/invoice_spec.rb +32 -0
  54. data/spec/models/avalara/request/line_spec.rb +25 -0
  55. data/spec/models/avalara_spec.rb +300 -0
  56. data/spec/spec_helper.rb +19 -0
  57. data/spec/support/avalara.rb +38 -0
  58. data/spec/support/factory_girl.rb +20 -0
  59. data/spec/support/vcr.rb +18 -0
  60. data/vizjerai-avalara.gemspec +31 -0
  61. metadata +257 -0
@@ -0,0 +1,73 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://API_BASIC_AUTH@API_ENDPOINT/1.0/tax/get
6
+ body:
7
+ encoding: UTF-8
8
+ string: ! "{\n \"CustomerCode\": null,\n \"DocDate\": \"2013-06-11\",\n \"CompanyCode\":
9
+ 83,\n \"Lines\": [\n {\n \"LineNo\": \"1\",\n \"DestinationCode\":
10
+ \"1\",\n \"OriginCode\": \"1\",\n \"Qty\": \"1\",\n \"Amount\":
11
+ 10\n }\n ],\n \"Addresses\": [\n {\n \"AddressCode\": 1,\n \"Line1\":
12
+ \"435 Ericksen Avenue Northeast\",\n \"Line2\": \"#250\",\n \"PostalCode\":
13
+ \"98110\"\n }\n ]\n}"
14
+ headers:
15
+ Accept:
16
+ - application/json
17
+ Content-Type:
18
+ - text/json
19
+ Date:
20
+ - Tue, 11 Jun 2013 14:25:21 GMT
21
+ User-Agent:
22
+ - avalara/0.0.2 (Rubygems; Ruby 1.9.3 x86_64-freebsd8.1)
23
+ Content-Length:
24
+ - '374'
25
+ response:
26
+ status:
27
+ code: 500
28
+ message: Internal Server Error
29
+ headers:
30
+ Cache-Control:
31
+ - private
32
+ Content-Type:
33
+ - text/json; charset=utf-8
34
+ X-Aspnet-Version:
35
+ - 4.0.30319
36
+ X-Powered-By:
37
+ - ASP.NET
38
+ Date:
39
+ - Tue, 11 Jun 2013 14:25:21 GMT
40
+ Content-Length:
41
+ - '215'
42
+ Set-Cookie:
43
+ - TS6198e2=6b8238c1ba9f886ffe742e8d094cc3fa3a10d0eeb29e4ce851b73351; Path=/
44
+ - TS6198e2_28=adb1456b4bb2ed5d9ad7bfb38be60cdc3a10d0eeb29e4ce800000000000000000051b73351cf2467f60807d03e;
45
+ Path=/
46
+ body:
47
+ encoding: US-ASCII
48
+ string: ! '{
49
+
50
+ "ResultCode": "Error",
51
+
52
+ "Messages": [
53
+
54
+ {
55
+
56
+ "Summary": "CustomerCode is required.",
57
+
58
+ "Details": "This value must be specified.",
59
+
60
+ "RefersTo": "CustomerCode",
61
+
62
+ "Severity": "Error",
63
+
64
+ "Source": "Avalara.AvaTax.Services"}
65
+
66
+ ]
67
+
68
+ }
69
+
70
+ '
71
+ http_version:
72
+ recorded_at: Tue, 11 Jun 2013 14:25:22 GMT
73
+ recorded_with: VCR 2.5.0
@@ -0,0 +1,76 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://API_BASIC_AUTH@API_ENDPOINT/1.0/address/validate?Line1=435%20Ericksen%20Avenue%20Northeast&Line2=%23250&PostalCode=98110
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Content-Type:
13
+ - text/json
14
+ Date:
15
+ - Tue, 11 Jun 2013 19:07:56 GMT
16
+ User-Agent:
17
+ - avalara/0.0.2 (Rubygems; Ruby 1.9.3 x86_64-freebsd8.1)
18
+ Content-Length:
19
+ - '0'
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Cache-Control:
26
+ - private
27
+ Content-Type:
28
+ - text/json; charset=utf-8
29
+ X-Aspnet-Version:
30
+ - 4.0.30319
31
+ X-Powered-By:
32
+ - ASP.NET
33
+ Date:
34
+ - Tue, 11 Jun 2013 19:07:56 GMT
35
+ Content-Length:
36
+ - '297'
37
+ Set-Cookie:
38
+ - TS6198e2=636d7e08a1ba939e74f09679205034ff17aef1bec375cc4e51b7758d; Path=/
39
+ - TS6198e2_28=d504e6ad8384879a66c8f948ac046f1317aef1bec375cc4e00000000000000000051b7758c8a73661fdfaad314;
40
+ Path=/
41
+ body:
42
+ encoding: US-ASCII
43
+ string: ! '{
44
+
45
+ "ResultCode": "Success",
46
+
47
+ "Address": {
48
+
49
+ "Line1": "250",
50
+
51
+ "Line2": "435 Ericksen Ave NE",
52
+
53
+ "City": "Bainbridge Island",
54
+
55
+ "Region": "WA",
56
+
57
+ "PostalCode": "98110-1896",
58
+
59
+ "Country": "US",
60
+
61
+ "County": "Kitsap",
62
+
63
+ "FipsCode": "5303500000",
64
+
65
+ "CarrierRoute": "C051",
66
+
67
+ "PostNet": "981101896999",
68
+
69
+ "AddressType": "H"}
70
+
71
+ }
72
+
73
+ '
74
+ http_version:
75
+ recorded_at: Tue, 11 Jun 2013 19:07:57 GMT
76
+ recorded_with: VCR 2.5.0
@@ -0,0 +1,68 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://API_BASIC_AUTH@API_ENDPOINT/1.0/address/validate?Line1=435%20Ericksen%20Avenue%20Northeast&Line2=%23250&PostalCode=
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Content-Type:
13
+ - text/json
14
+ Date:
15
+ - Tue, 11 Jun 2013 19:07:54 GMT
16
+ User-Agent:
17
+ - avalara/0.0.2 (Rubygems; Ruby 1.9.3 x86_64-freebsd8.1)
18
+ Content-Length:
19
+ - '0'
20
+ response:
21
+ status:
22
+ code: 500
23
+ message: Internal Server Error
24
+ headers:
25
+ Cache-Control:
26
+ - private
27
+ Content-Type:
28
+ - text/json; charset=utf-8
29
+ X-Aspnet-Version:
30
+ - 4.0.30319
31
+ X-Powered-By:
32
+ - ASP.NET
33
+ Date:
34
+ - Tue, 11 Jun 2013 19:07:55 GMT
35
+ Content-Length:
36
+ - '253'
37
+ Set-Cookie:
38
+ - TS6198e2=927716e1d83dd5e3fa61af30db5ced304c62f84ba8d8a59b51b7758b; Path=/
39
+ - TS6198e2_28=22ec2375be97493e8f7a884bc8271dc54c62f84ba8d8a59b00000000000000000051b7758b2814d6a370a5270d;
40
+ Path=/
41
+ body:
42
+ encoding: US-ASCII
43
+ string: ! '{
44
+
45
+ "ResultCode": "Error",
46
+
47
+ "Messages": [
48
+
49
+ {
50
+
51
+ "Summary": "Insufficient address information",
52
+
53
+ "Details": "You must specify at least Line/ZIP, or Line/City/State",
54
+
55
+ "RefersTo": "PostalCode",
56
+
57
+ "Severity": "Error",
58
+
59
+ "Source": "Avalara.AvaTax.Services.Address"}
60
+
61
+ ]
62
+
63
+ }
64
+
65
+ '
66
+ http_version:
67
+ recorded_at: Tue, 11 Jun 2013 19:07:56 GMT
68
+ recorded_with: VCR 2.5.0
@@ -0,0 +1,55 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Avalara::Configuration do
6
+ let(:configuration) { Avalara::Configuration.new }
7
+
8
+ context '#endpoint' do
9
+ it 'defaults to https://rest.avalara.net' do
10
+ configuration.endpoint.should == 'https://rest.avalara.net'
11
+ end
12
+
13
+ it 'may be overridden' do
14
+ expect {
15
+ configuration.endpoint = 'https://example.local/'
16
+ }.to change(configuration, :endpoint).to('https://example.local/')
17
+ end
18
+ end
19
+
20
+ context '#version' do
21
+ it 'defaults to 1.0' do
22
+ configuration.version.should == '1.0'
23
+ end
24
+
25
+ it 'may be overridden' do
26
+ expect {
27
+ configuration.version = '2.0'
28
+ }.to change(configuration, :version).to('2.0')
29
+ end
30
+ end
31
+
32
+ context '#username' do
33
+ it 'is unset by default' do
34
+ configuration.username.should be_nil
35
+ end
36
+
37
+ it 'may be set' do
38
+ expect {
39
+ configuration.username = 'abcdefg'
40
+ }.to change(configuration, :username).to('abcdefg')
41
+ end
42
+ end
43
+
44
+ context '#password' do
45
+ it 'is unset by default' do
46
+ configuration.password.should be_nil
47
+ end
48
+
49
+ it 'may be set' do
50
+ expect {
51
+ configuration.password = 'abcdefg'
52
+ }.to change(configuration, :password).to('abcdefg')
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Avalara::Request::Address do
6
+ let(:params) { FactoryGirl.attributes_for(:address) }
7
+ let(:address) { FactoryGirl.build_via_new(:address) }
8
+
9
+ context 'sets all attributes' do
10
+ subject { address }
11
+
12
+ its(:Line1) { should == params[:line_1] }
13
+ its(:Line2) { should == params[:line_2] }
14
+ its(:Line3) { should == params[:line_3] }
15
+ its(:City) { should == params[:city] }
16
+ its(:Region) { should == params[:region] }
17
+ its(:Country) { should == params[:country] }
18
+ its(:PostalCode) { should == params[:postal_code] }
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Avalara::Request::DetailLevel do
6
+ let(:params) { FactoryGirl.attributes_for(:detail_level) }
7
+ let(:detail_level) { FactoryGirl.build_via_new(:detail_level) }
8
+
9
+ context 'sets all attributes' do
10
+ subject { detail_level }
11
+
12
+ its(:Line) { should == params[:line] }
13
+ its(:Summary) { should == params[:summary] }
14
+ its(:Document) { should == params[:document] }
15
+ its(:Tax) { should == params[:tax] }
16
+ its(:Diagnostic) { should == params[:diagnostic] }
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Avalara::Request::InvoiceAddress do
6
+ let(:params) { FactoryGirl.attributes_for(:invoice_address) }
7
+ let(:invoice_address) { FactoryGirl.build_via_new(:invoice_address) }
8
+
9
+ context 'sets all attributes' do
10
+ subject { invoice_address }
11
+
12
+ its(:AddressCode) { should == params[:address_code] }
13
+ its(:Line1) { should == params[:line_1] }
14
+ its(:Line2) { should == params[:line_2] }
15
+ its(:Line3) { should == params[:line_3] }
16
+ its(:City) { should == params[:city] }
17
+ its(:Region) { should == params[:region] }
18
+ its(:Country) { should == params[:country] }
19
+ its(:PostalCode) { should == params[:postal_code] }
20
+ its(:Latitude) { should == params[:latitude] }
21
+ its(:Longitude) { should == params[:longitude] }
22
+ its(:TaxRegionId) { should == params[:tax_region_id] }
23
+ end
24
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Avalara::Request::Invoice do
6
+ let(:params) { FactoryGirl.attributes_for(:invoice) }
7
+ let(:invoice) { FactoryGirl.build_via_new(:invoice) }
8
+
9
+ context 'sets all attributes' do
10
+ subject { invoice }
11
+
12
+ its(:CustomerCode) { should == params[:customer_code] }
13
+ its(:DocDate) { should == Avalara::Types::Date.coerce(params[:doc_date]) }
14
+ its(:CompanyCode) { should == params[:company_code] }
15
+ its(:Commit) { should == params[:commit] }
16
+ its(:CustomerUsageType) { should == params[:customer_usage_type] }
17
+ its(:Discount) { should == params[:discount] }
18
+ its(:DocCode) { should == params[:doc_code] }
19
+ its(:PurchaseOrderNo) { should == params[:purchase_order_no] }
20
+ its(:ExemptionNo) { should == params[:exemption_no] }
21
+ its(:DetailLevel) { should == params[:detail_level] }
22
+ its(:DocType) { should == params[:doc_type] }
23
+ its(:Lines) { should == params[:lines] }
24
+ its(:Addresses) { should == params[:addresses] }
25
+ its(:ReferenceCode) { should == params[:reference_code] }
26
+ end
27
+
28
+ context 'converts nested objects to json' do
29
+ subject { invoice.to_json }
30
+ it { should_not be_nil }
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Avalara::Request::Line do
6
+ let(:params) { FactoryGirl.attributes_for(:line) }
7
+ let(:line) { FactoryGirl.build_via_new(:line) }
8
+
9
+ context 'sets all attributes' do
10
+ subject { line }
11
+
12
+ its(:LineNo) { should == params[:line_no] }
13
+ its(:DestinationCode) { should == params[:destination_code] }
14
+ its(:OriginCode) { should == params[:origin_code] }
15
+ its(:ItemCode) { should == params[:item_code] }
16
+ its(:TaxCode) { should == params[:tax_code] }
17
+ its(:CustomerUsageType) { should == params[:customer_usage_type] }
18
+ its(:Qty) { should == params[:qty] }
19
+ its(:Amount) { should == params[:amount] }
20
+ its(:Discounted) { should == params[:discounted] }
21
+ its(:TaxIncluded) { should == params[:tax_included] }
22
+ its(:Ref1) { should == params[:ref_1] }
23
+ its(:Ref2) { should == params[:ref_2] }
24
+ end
25
+ end
@@ -0,0 +1,300 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Avalara do
6
+ maintain_contactology_configuration
7
+
8
+ let(:configuration) { Avalara.configuration }
9
+
10
+ describe '.configuration' do
11
+ it 'yields a Avalara::Configuration instance' do
12
+ Avalara.configuration do |yielded|
13
+ yielded.should be_kind_of Avalara::Configuration
14
+ end
15
+ end
16
+
17
+ it 'yields the same configuration instance across multiple calls' do
18
+ Avalara.configuration do |config|
19
+ Avalara.configuration do |config2|
20
+ config.object_id.should == config2.object_id
21
+ end
22
+ end
23
+ end
24
+
25
+ it 'returns the configuration when queried' do
26
+ Avalara.configuration do |config|
27
+ Avalara.configuration.object_id.should == config.object_id
28
+ end
29
+ end
30
+
31
+ it 'may be explicitly overridden' do
32
+ configuration = Avalara::Configuration.new
33
+ expect {
34
+ Avalara.configuration = configuration
35
+ }.to change(Avalara, :configuration).to(configuration)
36
+ end
37
+
38
+ it 'raises an ArgumentError when set to a non-Configuration object' do
39
+ expect {
40
+ Avalara.configuration = 'bad'
41
+ }.to raise_error(ArgumentError)
42
+ end
43
+ end
44
+
45
+ describe '.endpoint' do
46
+ it 'returns the configuration endpoint' do
47
+ Avalara.endpoint.should == configuration.endpoint
48
+ end
49
+
50
+ it 'overrides the configuration endpoint' do
51
+ expect {
52
+ Avalara.endpoint = 'https://example.local/'
53
+ }.to change(configuration, :endpoint).to('https://example.local/')
54
+ end
55
+ end
56
+
57
+ describe '.username' do
58
+ it 'returns the configuration username' do
59
+ configuration.username = 'username'
60
+ Avalara.username.should == configuration.username
61
+ end
62
+
63
+ it 'overrides the configuration username' do
64
+ expect {
65
+ Avalara.username = 'username'
66
+ }.to change(configuration, :username).to('username')
67
+ end
68
+ end
69
+
70
+ describe '.password' do
71
+ it 'returns the configuration password' do
72
+ configuration.password = 'password'
73
+ Avalara.password.should == configuration.password
74
+ end
75
+
76
+ it 'overrides the configuration password' do
77
+ expect {
78
+ Avalara.password = 'password'
79
+ }.to change(configuration, :password).to('password')
80
+ end
81
+ end
82
+
83
+ describe '.version' do
84
+ it 'returns the configuration version' do
85
+ configuration.version = 'version'
86
+ Avalara.version.should == configuration.version
87
+ end
88
+
89
+ it 'overrides the configuration version' do
90
+ expect {
91
+ Avalara.version = 'version'
92
+ }.to change(configuration, :version).to('version')
93
+ end
94
+ end
95
+
96
+ describe '.cancel_tax' do
97
+ let(:cancel_tax) { FactoryGirl.build_via_new(:cancel_tax) }
98
+ let(:request) { Avalara.cancel_tax(cancel_tax) }
99
+
100
+ it 'successful response', :vcr do
101
+ expect(request).to be_a Avalara::Response::CancelTax
102
+ expect(request).to be_success
103
+
104
+ expect(request.transaction_id).to be 431361022
105
+ expect(request.doc_id).to eq '34279849'
106
+ expect(request.result_code).to eq 'Success'
107
+ expect(request.messages).to be_nil
108
+ end
109
+
110
+ context 'with missing doc code', :vcr do
111
+ let(:cancel_tax) { FactoryGirl.build_via_new(:cancel_tax, :doc_code => nil) }
112
+ it 'unsuccessful response' do
113
+ expect(request).to be_a Avalara::Response::CancelTax
114
+ expect(request).to_not be_success
115
+
116
+ expect(request.transaction_id).to be 431377420
117
+ expect(request.doc_id).to be_nil
118
+ expect(request.result_code).to eq 'Error'
119
+ expect(request).to have(1).message
120
+
121
+ message = request.messages.first
122
+ expect(message.details).to eq "This value must be specified."
123
+ expect(message.refers_to).to eq "DocCode"
124
+ expect(message.severity).to eq "Error"
125
+ expect(message.source).to eq "Avalara.AvaTax.Services"
126
+ expect(message.summary).to eq "DocCode is required."
127
+ end
128
+ end
129
+
130
+ context 'on timeout' do
131
+ it 'raises an avalara timeout error' do
132
+ Avalara::API.should_receive(:post).and_raise(Timeout::Error)
133
+ expect { request }.to raise_error(Avalara::TimeoutError)
134
+ end
135
+ end
136
+ end
137
+
138
+ describe '.get_tax' do
139
+ let(:doc_date) { Date.parse("January 1, 2012") }
140
+ let(:invoice) { FactoryGirl.build_via_new(:invoice, :doc_date => doc_date) }
141
+ let(:request) { Avalara.get_tax(invoice) }
142
+
143
+ it 'successful response', :vcr do
144
+ expect(request).to be_kind_of Avalara::Response::Invoice
145
+ expect(request).to be_success
146
+
147
+ expect(request.doc_code).to_not be_nil
148
+ expect(request.doc_date).to eq "2012-01-01"
149
+ expect(request.result_code).to eq "Success"
150
+ expect(request.tax_date).to_not be_nil
151
+ expect(request.timestamp).to_not be_nil
152
+ expect(request.total_amount).to eq "10"
153
+ expect(request.total_discount).to eq "0"
154
+ expect(request.total_exemption).to eq "10"
155
+ expect(request.total_tax).to eq "0"
156
+ expect(request.total_tax_calculated).to eq "0"
157
+ expect(request.tax_lines.length).to be 1
158
+
159
+ tax_line = request.tax_lines.first
160
+ expect(tax_line.line_no).to eq "1"
161
+ expect(tax_line.tax_code).to eq "P0000000"
162
+ expect(tax_line.taxability).to eq "true"
163
+ expect(tax_line.taxable).to eq "0"
164
+ expect(tax_line.rate).to eq "0"
165
+ expect(tax_line.tax).to eq "0"
166
+ expect(tax_line.discount).to eq "0"
167
+ expect(tax_line.tax_calculated).to eq "0"
168
+ expect(tax_line.exemption).to eq "10"
169
+ expect(tax_line.tax_details.length).to be 1
170
+
171
+ tax_detail = tax_line.tax_details.first
172
+ expect(tax_detail.taxable).to eq "0"
173
+ expect(tax_detail.rate).to eq "0"
174
+ expect(tax_detail.tax).to eq "0"
175
+ expect(tax_detail.region).to eq "WA"
176
+ expect(tax_detail.country).to eq "US"
177
+ expect(tax_detail.juris_type).to eq "State"
178
+ expect(tax_detail.juris_name).to eq "WASHINGTON"
179
+ expect(tax_detail.tax_name).to eq "WA STATE TAX"
180
+
181
+ expect(request.tax_addresses.length).to be 1
182
+ end
183
+
184
+ context 'with missing required field', :vcr do
185
+ let(:invoice) { FactoryGirl.build_via_new(:invoice, customer_code: nil) }
186
+
187
+ it 'unsuccessful response' do
188
+ expect(request).to be_kind_of Avalara::Response::Invoice
189
+ expect(request).to_not be_success
190
+
191
+ message = request.messages.first
192
+ expect(message.details).to eq "This value must be specified."
193
+ expect(message.refers_to).to eq "CustomerCode"
194
+ expect(message.severity).to eq "Error"
195
+ expect(message.source).to eq "Avalara.AvaTax.Services"
196
+ expect(message.summary).to eq "CustomerCode is required."
197
+ end
198
+ end
199
+
200
+ context 'on timeout' do
201
+ it 'raises an avalara timeout error' do
202
+ Avalara::API.should_receive(:post).and_raise(Timeout::Error)
203
+ expect { request }.to raise_error(Avalara::TimeoutError)
204
+ end
205
+ end
206
+ end
207
+
208
+ describe '.geographical_tax' do
209
+ let(:latitude) { '47.627935' }
210
+ let(:longitude) { '-122.51702' }
211
+ let(:sales_amount) { 100 }
212
+ let(:request) { Avalara.geographical_tax(latitude, longitude, sales_amount) }
213
+
214
+ it 'successful response', :vcr do
215
+ expect(request).to be_kind_of Avalara::Response::Tax
216
+ expect(request).to be_success
217
+
218
+ expect(request.rate).to eq 0.086
219
+ expect(request.tax).to eq 8.6
220
+ expect(request.tax_details).to have(2).items
221
+
222
+ state_tax_detail = request.tax_details.first
223
+ expect(state_tax_detail.rate).to eq 0.065
224
+ expect(state_tax_detail.tax).to eq 6.5
225
+ expect(state_tax_detail.juris_type).to eq 'State'
226
+
227
+ city_tax_detail = request.tax_details.last
228
+ expect(city_tax_detail.rate).to eq 0.021
229
+ expect(city_tax_detail.tax).to eq 2.1
230
+ expect(city_tax_detail.juris_type).to eq 'City'
231
+ end
232
+
233
+ context 'with incomplete address', :vcr do
234
+ let(:longitude) { '122.51702' }
235
+
236
+ it 'unsuccessful response' do
237
+ expect(request).to be_kind_of Avalara::Response::Tax
238
+ expect(request).to_not be_success
239
+
240
+ expect(request.rate).to be_nil
241
+ expect(request.tax).to be_nil
242
+ expect(request.tax_details).to be_nil
243
+ end
244
+ end
245
+
246
+ context 'on timeout' do
247
+ let(:longitude) { '-122.51702' }
248
+ it 'raises an avalara timeout error' do
249
+ Avalara::API.should_receive(:get).and_raise(Timeout::Error)
250
+ expect { request }.to raise_error(Avalara::TimeoutError)
251
+ end
252
+ end
253
+ end
254
+
255
+ describe '.validate_address' do
256
+ let(:address) { FactoryGirl.build_via_new(:address) }
257
+ let(:request) { Avalara.validate_address(address) }
258
+
259
+ it 'successful response', :vcr do
260
+ expect(request).to be_kind_of Avalara::Response::AddressValidation
261
+ expect(request).to be_success
262
+
263
+ expect(request.address).to be_a Avalara::Response::ValidationAddress
264
+
265
+ address = request.address
266
+ expect(address.line_1).to eq '250'
267
+ expect(address.line_2).to eq '435 Ericksen Ave NE'
268
+ expect(address.line_3).to be_nil
269
+ expect(address.city).to eq 'Bainbridge Island'
270
+ expect(address.region).to eq 'WA'
271
+ expect(address.country).to eq 'US'
272
+ expect(address.address_type).to eq 'H'
273
+ expect(address.address_type_name).to eq 'High-rise or business complex'
274
+ expect(address.postal_code).to eq '98110-1896'
275
+ expect(address.county).to eq 'Kitsap'
276
+ expect(address.fips_code).to eq '5303500000'
277
+ expect(address.carrier_route).to eq 'C051'
278
+ expect(address.carrier_route_name).to eq 'City delivery'
279
+ expect(address.tax_region_id).to be_nil
280
+ expect(address.post_net).to eq '981101896999'
281
+ end
282
+
283
+ context 'with missing postal code', :vcr do
284
+ let(:address) { FactoryGirl.build_via_new(:address, :postal_code => nil) }
285
+
286
+ it 'unsuccessful response' do
287
+ expect(request).to be_kind_of Avalara::Response::AddressValidation
288
+ expect(request).to_not be_success
289
+ end
290
+ end
291
+
292
+ context 'on timeout' do
293
+ it 'raises an avalara timeout error' do
294
+ Avalara::API.should_receive(:get).and_raise(Timeout::Error)
295
+ expect { request }.to raise_error(Avalara::TimeoutError)
296
+ end
297
+ end
298
+ end
299
+
300
+ end