workarea-avatax 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  4. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.github/workflows/ci.yml +66 -0
  7. data/.gitignore +18 -0
  8. data/.rubocop.yml +8 -0
  9. data/CHANGELOG.md +123 -0
  10. data/CODE_OF_CONDUCT.md +3 -0
  11. data/CONTRIBUTING.md +3 -0
  12. data/Gemfile +10 -0
  13. data/LICENSE.md +3 -0
  14. data/README.md +57 -0
  15. data/Rakefile +50 -0
  16. data/app/models/workarea/avatax/usage_type.rb +17 -0
  17. data/app/models/workarea/pricing/calculators/avalara_tax_calculator.rb +105 -0
  18. data/app/models/workarea/user.decorator +7 -0
  19. data/app/seeds/workarea/avatax_seeds.rb +44 -0
  20. data/app/view_models/workarea/admin/user_view_model.decorator +21 -0
  21. data/app/view_models/workarea/storefront/cart_view_model.decorator +7 -0
  22. data/app/views/workarea/admin/users/_avatax_properties_fields.html.haml +5 -0
  23. data/app/workers/workarea/avatax/tax_invoice_worker.rb +29 -0
  24. data/bin/rails +17 -0
  25. data/config/initializers/appends.rb +4 -0
  26. data/config/initializers/avatax.rb +14 -0
  27. data/config/initializers/seeds.rb +1 -0
  28. data/config/locales/en.yml +6 -0
  29. data/lib/avatax/api.decorator +52 -0
  30. data/lib/workarea/avatax/bogus_gateway/bogus_create_transaction.rb +187 -0
  31. data/lib/workarea/avatax/bogus_gateway.rb +34 -0
  32. data/lib/workarea/avatax/engine.rb +36 -0
  33. data/lib/workarea/avatax/tax_request/addresses.rb +35 -0
  34. data/lib/workarea/avatax/tax_request/line_item.rb +47 -0
  35. data/lib/workarea/avatax/tax_request/order_line_item.rb +64 -0
  36. data/lib/workarea/avatax/tax_request/order_lines.rb +70 -0
  37. data/lib/workarea/avatax/tax_request/response.rb +49 -0
  38. data/lib/workarea/avatax/tax_request/shipping_line_item.rb +34 -0
  39. data/lib/workarea/avatax/tax_request.rb +77 -0
  40. data/lib/workarea/avatax/version.rb +5 -0
  41. data/lib/workarea/avatax.rb +71 -0
  42. data/test/dummy/Rakefile +6 -0
  43. data/test/dummy/bin/bundle +3 -0
  44. data/test/dummy/bin/rails +4 -0
  45. data/test/dummy/bin/rake +4 -0
  46. data/test/dummy/bin/setup +34 -0
  47. data/test/dummy/bin/update +29 -0
  48. data/test/dummy/config/application.rb +23 -0
  49. data/test/dummy/config/boot.rb +5 -0
  50. data/test/dummy/config/cable.yml +9 -0
  51. data/test/dummy/config/environment.rb +5 -0
  52. data/test/dummy/config/environments/development.rb +54 -0
  53. data/test/dummy/config/environments/production.rb +86 -0
  54. data/test/dummy/config/environments/test.rb +44 -0
  55. data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
  56. data/test/dummy/config/initializers/assets.rb +11 -0
  57. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  58. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  59. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  60. data/test/dummy/config/initializers/inflections.rb +16 -0
  61. data/test/dummy/config/initializers/mime_types.rb +4 -0
  62. data/test/dummy/config/initializers/new_framework_defaults.rb +23 -0
  63. data/test/dummy/config/initializers/workarea.rb +5 -0
  64. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  65. data/test/dummy/config/locales/en.yml +23 -0
  66. data/test/dummy/config/puma.rb +47 -0
  67. data/test/dummy/config/routes.rb +5 -0
  68. data/test/dummy/config/secrets.yml +22 -0
  69. data/test/dummy/config/spring.rb +6 -0
  70. data/test/dummy/config.ru +5 -0
  71. data/test/dummy/db/seeds.rb +2 -0
  72. data/test/dummy/lib/assets/.keep +0 -0
  73. data/test/dummy/log/.keep +0 -0
  74. data/test/dummy/public/404.html +67 -0
  75. data/test/dummy/public/422.html +67 -0
  76. data/test/dummy/public/500.html +66 -0
  77. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  78. data/test/dummy/public/apple-touch-icon.png +0 -0
  79. data/test/dummy/public/favicon.ico +0 -0
  80. data/test/factories/workarea/avatax_factories.rb +142 -0
  81. data/test/lib/workarea/avatax/tax_request/order_line_items_test.rb +114 -0
  82. data/test/lib/workarea/avatax/tax_request/response_test.rb +42 -0
  83. data/test/lib/workarea/avatax/tax_request_test.rb +51 -0
  84. data/test/lib/workarea/avatax_test.rb +28 -0
  85. data/test/models/workarea/avatax/usage_type_test.rb +13 -0
  86. data/test/models/workarea/pricing/calculators/avalara_tax_calculator_test.rb +113 -0
  87. data/test/support/avatax_test_settings.rb +9 -0
  88. data/test/system/workarea/storefront/avatax_system_test.rb +22 -0
  89. data/test/test_helper.rb +20 -0
  90. data/test/vcr_cassettes/succesful_avatax_create_transaction.yml +60 -0
  91. data/test/vcr_cassettes/succesful_avatax_create_transaction_multiple_shippings.yml +76 -0
  92. data/workarea-avatax.gemspec +20 -0
  93. metadata +176 -0
@@ -0,0 +1,47 @@
1
+ # Puma can serve each request in a thread from an internal thread pool.
2
+ # The `threads` method setting takes two numbers a minimum and maximum.
3
+ # Any libraries that use thread pools should be configured to match
4
+ # the maximum value specified for Puma. Default is set to 5 threads for minimum
5
+ # and maximum, this matches the default thread size of Active Record.
6
+ #
7
+ threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
8
+ threads threads_count, threads_count
9
+
10
+ # Specifies the `port` that Puma will listen on to receive requests, default is 3000.
11
+ #
12
+ port ENV.fetch("PORT") { 3000 }
13
+
14
+ # Specifies the `environment` that Puma will run in.
15
+ #
16
+ environment ENV.fetch("RAILS_ENV") { "development" }
17
+
18
+ # Specifies the number of `workers` to boot in clustered mode.
19
+ # Workers are forked webserver processes. If using threads and workers together
20
+ # the concurrency of the application would be max `threads` * `workers`.
21
+ # Workers do not work on JRuby or Windows (both of which do not support
22
+ # processes).
23
+ #
24
+ # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
25
+
26
+ # Use the `preload_app!` method when specifying a `workers` number.
27
+ # This directive tells Puma to first boot the application and load code
28
+ # before forking the application. This takes advantage of Copy On Write
29
+ # process behavior so workers use less memory. If you use this option
30
+ # you need to make sure to reconnect any threads in the `on_worker_boot`
31
+ # block.
32
+ #
33
+ # preload_app!
34
+
35
+ # The code in the `on_worker_boot` will be called if you are using
36
+ # clustered mode by specifying a number of `workers`. After each worker
37
+ # process is booted this block will be run, if you are using `preload_app!`
38
+ # option you will want to use this block to reconnect to any threads
39
+ # or connections that may have been created at application boot, Ruby
40
+ # cannot share connections between processes.
41
+ #
42
+ # on_worker_boot do
43
+ # ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
44
+ # end
45
+
46
+ # Allow puma to be restarted by `rails restart` command.
47
+ plugin :tmp_restart
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ mount Workarea::Core::Engine => "/"
3
+ mount Workarea::Admin::Engine => "/admin", as: "admin"
4
+ mount Workarea::Storefront::Engine => "/", as: "storefront"
5
+ end
@@ -0,0 +1,22 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key is used for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+
6
+ # Make sure the secret is at least 30 characters and all random,
7
+ # no regular words or you'll be exposed to dictionary attacks.
8
+ # You can use `rails secret` to generate a secure secret key.
9
+
10
+ # Make sure the secrets in this file are kept private
11
+ # if you're sharing your code publicly.
12
+
13
+ development:
14
+ secret_key_base: e95d581460a83a669c20fbfd42ecbcd0195f257a2c1faa77a1be3d3d184c6d92231259bffe312d7730990a87997c1d38f442d6bcf6151ff9e07793f43b26d1be
15
+
16
+ test:
17
+ secret_key_base: a8af256aec30ccf03fe1d713da17fbd4c6b1ed475cd83933f95ed7b9d9781184a27ae1d9e5f8fc74280bfc420992bfa694123ef6a652e60707bcbdacbf8f7263
18
+
19
+ # Do not keep production secrets in the repository,
20
+ # instead read values from the environment.
21
+ production:
22
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
@@ -0,0 +1,6 @@
1
+ %w(
2
+ .ruby-version
3
+ .rbenv-vars
4
+ tmp/restart.txt
5
+ tmp/caching-dev.txt
6
+ ).each { |path| Spring.watch(path) }
@@ -0,0 +1,5 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require_relative "config/environment"
4
+
5
+ run Rails.application
@@ -0,0 +1,2 @@
1
+ require "workarea/seeds"
2
+ Workarea::Seeds.run
File without changes
File without changes
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/404.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The page you were looking for doesn't exist.</h1>
62
+ <p>You may have mistyped the address or the page may have moved.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/422.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The change you wanted was rejected.</h1>
62
+ <p>Maybe you tried to change something you didn't have access to.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/500.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
64
+ </div>
65
+ </body>
66
+ </html>
File without changes
File without changes
@@ -0,0 +1,142 @@
1
+ module Workarea
2
+ module Factories
3
+ module AvataxFactories
4
+ Factories.add self
5
+
6
+ def create_checkout_order(overrides = {})
7
+ attributes = overrides
8
+
9
+ shipping_service = create_shipping_service(tax_code: "P0000000")
10
+ sku = "SKU1"
11
+ product = create_product(variants: [{ sku: sku, regular: 5.to_m, tax_code: "P0000000" }])
12
+
13
+ Workarea::Order.new(attributes).tap do |order|
14
+ shipping = Workarea::Shipping.create!(order_id: order.id)
15
+
16
+ shipping.set_shipping_service(
17
+ id: shipping_service.id,
18
+ name: shipping_service.name,
19
+ base_price: shipping_service.rates.first.price,
20
+ tax_code: shipping_service.tax_code
21
+ )
22
+
23
+ order.items.build(
24
+ product_id: product.id,
25
+ sku: sku,
26
+ quantity: 2,
27
+ product_attributes: product.as_document
28
+ )
29
+
30
+ shipping.set_address(
31
+ first_name: "Eric",
32
+ last_name: "Pigeon",
33
+ street: "22 S 3rd St",
34
+ city: "Philadelphia",
35
+ region: "PA",
36
+ postal_code: 19106,
37
+ country: "US"
38
+ )
39
+
40
+ Workarea::Pricing.perform(order)
41
+
42
+ order.save!
43
+ end
44
+ end
45
+
46
+ def create_split_shipping_checkout_order(overrides = {})
47
+ attributes = { email: "epigeon@workarea.com" }.merge overrides
48
+ product_1 = create_product(
49
+ id: "PROD1",
50
+ name: "Split Shipping Product One",
51
+ variants: [{ sku: "SKU1", regular: 5.to_m, tax_code: "001" }]
52
+ )
53
+ product_2 = create_product(
54
+ id: "PROD2",
55
+ name: "Split Shipping Product Two",
56
+ variants: [{ sku: "SKU2", regular: 7.to_m, tax_code: "001" }]
57
+ )
58
+ product_3 = create_product(
59
+ id: "PROD3",
60
+ name: "Split Shipping Product Three",
61
+ variants: [{ sku: "SKU3", regular: 9.to_m, tax_code: "001" }]
62
+ )
63
+ ground = create_shipping_service(name: "Ground", tax_code: "001", rates: [{ price: 5.to_m }])
64
+ express = create_shipping_service(name: "Express", tax_code: "001", rates: [{ price: 10.to_m }])
65
+
66
+ Workarea::Order.new(attributes).tap do |order|
67
+ order.items.build(
68
+ product_id: "PROD1",
69
+ sku: "SKU1",
70
+ quantity: 2,
71
+ product_attributes: product_1.as_document
72
+ )
73
+
74
+ order.items.build(
75
+ product_id: "PROD2",
76
+ sku: "SKU2",
77
+ quantity: 2,
78
+ product_attributes: product_2.as_document
79
+ )
80
+
81
+ order.items.build(
82
+ product_id: "PROD3",
83
+ sku: "SKU3",
84
+ quantity: 4,
85
+ product_attributes: product_3.as_document
86
+ )
87
+
88
+ shipping_1 = Workarea::Shipping.create!(
89
+ order_id: order.id,
90
+ quantities: {
91
+ order.items.first.id.to_s => 2,
92
+ order.items.second.id.to_s => 1
93
+ },
94
+ address: {
95
+ first_name: "Eric",
96
+ last_name: "Pigeon",
97
+ street: "22 S 3rd St",
98
+ city: "Philadelphia",
99
+ region: "PA",
100
+ postal_code: 19106,
101
+ country: "US"
102
+ }
103
+ )
104
+
105
+ shipping_1.set_shipping_service(
106
+ id: ground.id,
107
+ name: ground.name,
108
+ base_price: ground.rates.first.price,
109
+ tax_code: ground.tax_code
110
+ )
111
+
112
+ shipping_2 = Workarea::Shipping.create!(
113
+ order_id: order.id,
114
+ quantities: {
115
+ order.items.second.id.to_s => 1,
116
+ order.items.third.id.to_s => 4
117
+ },
118
+ address: {
119
+ first_name: "Eric",
120
+ last_name: "Pigeon",
121
+ street: "12 N 3rd St",
122
+ city: "Philadelphia",
123
+ region: "PA",
124
+ postal_code: 19106,
125
+ country: "US"
126
+ }
127
+ )
128
+
129
+ shipping_2.set_shipping_service(
130
+ id: express.id,
131
+ name: express.name,
132
+ base_price: express.rates.first.price,
133
+ tax_code: express.tax_code
134
+ )
135
+
136
+ Workarea::Pricing.perform(order)
137
+ order.save!
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,114 @@
1
+ require "test_helper"
2
+
3
+ module Workarea
4
+ module Avatax
5
+ class TaxRequest::OrderLinesTest < TestCase
6
+ def test_lines_with_single_shipping
7
+ order = create_checkout_order(email: "epigeon@weblinc.com")
8
+ shippings = Shipping.where(order_id: order.id)
9
+ order_line_items = TaxRequest::OrderLines.new(order, shippings)
10
+
11
+ assert_equal 2, order_line_items.lines.size
12
+ end
13
+
14
+ def test_lines_with_split_shippings
15
+ order = create_split_shipping_checkout_order
16
+ shippings = Shipping.where(order_id: order.id)
17
+ order_line_items = TaxRequest::OrderLines.new(order, shippings)
18
+
19
+ assert_equal 6, order_line_items.lines.size
20
+ expected_lines = [
21
+ {
22
+ quantity: 2,
23
+ amount: "10.00",
24
+ itemCode: "SKU1",
25
+ taxCode: "001",
26
+ description: "Split Shipping Product One",
27
+ number: 1,
28
+ addresses: {
29
+ shipTo: {
30
+ line1: "22 S 3rd St",
31
+ line2: nil,
32
+ city: "Philadelphia",
33
+ region: "PA",
34
+ country: "US",
35
+ postalCode: "19106"
36
+ }
37
+ }
38
+ },
39
+ {
40
+ quantity: 1,
41
+ amount: "7.00",
42
+ itemCode: "SKU2",
43
+ taxCode: "001",
44
+ description: "Split Shipping Product Two",
45
+ number: 2,
46
+ addresses: {
47
+ shipTo: {
48
+ line1: "22 S 3rd St",
49
+ line2: nil,
50
+ city: "Philadelphia",
51
+ region: "PA",
52
+ country: "US",
53
+ postalCode: "19106"
54
+ }
55
+ }
56
+ },
57
+ {
58
+ quantity: 1,
59
+ amount: "7.00",
60
+ itemCode: "SKU2",
61
+ taxCode: "001",
62
+ description: "Split Shipping Product Two",
63
+ number: 3,
64
+ addresses: {
65
+ shipTo: {
66
+ line1: "12 N 3rd St",
67
+ line2: nil,
68
+ city: "Philadelphia",
69
+ region: "PA",
70
+ country: "US",
71
+ postalCode: "19106"
72
+ }
73
+ }
74
+ },
75
+ {
76
+ quantity: 4,
77
+ amount: "36.00",
78
+ itemCode: "SKU3",
79
+ taxCode: "001",
80
+ description: "Split Shipping Product Three",
81
+ number: 4,
82
+ addresses: {
83
+ shipTo: {
84
+ line1: "12 N 3rd St",
85
+ line2: nil,
86
+ city: "Philadelphia",
87
+ region: "PA",
88
+ country: "US",
89
+ postalCode: "19106"
90
+ }
91
+ }
92
+ },
93
+ {
94
+ quantity: 1,
95
+ amount: "5.00",
96
+ itemCode: "SHIPPING",
97
+ taxCode: "001",
98
+ description: "Ground",
99
+ number: 5
100
+ },
101
+ {
102
+ quantity: 1,
103
+ amount: "10.00",
104
+ itemCode: "SHIPPING",
105
+ taxCode: "001",
106
+ description: "Express",
107
+ number: 6
108
+ }
109
+ ]
110
+ assert_equal expected_lines, order_line_items.lines.map(&:hash)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,42 @@
1
+ require "test_helper"
2
+
3
+ module Workarea
4
+ module Avatax
5
+ class TaxRequest::ResponseTest < Workarea::TestCase
6
+ setup :create_tax_rate
7
+
8
+ def test_tax_line_for_adjustment
9
+ response = TaxRequest.new(order: order, shippings: shippings).response
10
+
11
+ adjustment = order.price_adjustments.detect { |a| a.data["tax_code"].present? }
12
+ adjustment_tax_line = response.tax_line_for_adjustment(adjustment)
13
+ assert_equal "0.80", adjustment_tax_line.tax
14
+ end
15
+
16
+ def test_tax_line_for_shipping
17
+ response = TaxRequest.new(order: order, shippings: shippings).response
18
+
19
+ shipping = shippings.first
20
+ shipping_tax_line = response.tax_line_for_shipping(shipping)
21
+ assert_equal "0.08", shipping_tax_line.tax
22
+ end
23
+
24
+ private
25
+
26
+ def order
27
+ @order ||= create_checkout_order(email: "epigeon@weblinc.com")
28
+ end
29
+
30
+ def shippings
31
+ @shippings ||= Shipping.where(order_id: order.id)
32
+ end
33
+
34
+ def create_tax_rate
35
+ create_tax_category(
36
+ code: "P0000000",
37
+ rates: [{ percentage: 0.08, country: "US", region: "PA" }]
38
+ )
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,51 @@
1
+ require "test_helper"
2
+
3
+ module Workarea
4
+ module Avatax
5
+ class TaxRequestTest < Workarea::TestCase
6
+ setup :configure_sandbox
7
+ teardown :reset_avatax_config
8
+
9
+ def test_successful_response
10
+ order = create_checkout_order(email: "epigeon@weblinc.com")
11
+ shippings = Shipping.where(order_id: order.id)
12
+ request = TaxRequest.new(order: order, shippings: shippings)
13
+
14
+ response = VCR.use_cassette :succesful_avatax_create_transaction do
15
+ request.response
16
+ end
17
+
18
+ assert response.success?
19
+ end
20
+
21
+ def test_body_lines_split_shippings
22
+ order = create_split_shipping_checkout_order
23
+ shippings = Shipping.where(order_id: order.id)
24
+ request = TaxRequest.new(order: order, shippings: shippings)
25
+
26
+ response = VCR.use_cassette :succesful_avatax_create_transaction_multiple_shippings do
27
+ request.response
28
+ end
29
+
30
+ assert response.success?
31
+ end
32
+
33
+ private
34
+
35
+ def configure_sandbox
36
+ AvaTax.configure do |config|
37
+ config.endpoint = "https://sandbox-rest.avatax.com/"
38
+ config.username = "jyucis-lp-avatax@weblinc.com"
39
+ config.password = "Jm{m3NX.Q"
40
+ end
41
+
42
+ Avatax.gateway = ::AvaTax.client
43
+ end
44
+
45
+ def reset_avatax_config
46
+ AvaTax.reset
47
+ Avatax.gateway = Avatax::BogusGateway.new
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ require "test_helper"
2
+
3
+ module Workarea
4
+ class AvataxTest < Workarea::TestCase
5
+ def test_auto_configure_gateway_creates_bogus_gateway_without_secrets
6
+ assert_instance_of(Avatax::BogusGateway, Avatax.gateway)
7
+ end
8
+
9
+ def test_auto_configure_gateway_creates_real_gateway_with_secrets
10
+ Rails.application.secrets.merge!(
11
+ avatax: {
12
+ username: "epigeon@weblinc.com",
13
+ password: "648B0A9851",
14
+ endpoint: "https://sandbox-rest.avatax.com/"
15
+ }
16
+ )
17
+
18
+ Avatax.auto_configure_gateway
19
+ assert_instance_of(AvaTax::Client, Avatax.gateway)
20
+
21
+ assert_includes(Avatax.gateway.connection_options[:request].keys, :timeout)
22
+
23
+ ensure
24
+ Rails.application.secrets.delete(:avatax)
25
+ Avatax.gateway = Avatax::BogusGateway.new
26
+ end
27
+ end
28
+ end