workarea-zipco 1.0.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 (111) hide show
  1. checksums.yaml +7 -0
  2. data/.eslintrc.json +35 -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 +64 -0
  7. data/.gitignore +23 -0
  8. data/.rubocop.yml +2 -0
  9. data/.stylelintrc.json +8 -0
  10. data/CHANGELOG.md +17 -0
  11. data/Gemfile +17 -0
  12. data/README.md +51 -0
  13. data/Rakefile +59 -0
  14. data/app/assets/images/zipco/.keep +0 -0
  15. data/app/assets/stylesheets/workarea/storefront/zipco/components/_zipco_icon.scss +7 -0
  16. data/app/controllers/storefront/checkout/place_order_controller.decorator +11 -0
  17. data/app/controllers/storefront/zipco_controller.rb +96 -0
  18. data/app/controllers/storefront/zipco_landing_controller.rb +6 -0
  19. data/app/helpers/.keep +0 -0
  20. data/app/mailers/.keep +0 -0
  21. data/app/models/checkout.decorator +33 -0
  22. data/app/models/workarea/order.decorator +52 -0
  23. data/app/models/workarea/order/status/zip_referred.rb +13 -0
  24. data/app/models/workarea/payment.decorator +30 -0
  25. data/app/models/workarea/payment/authorize/zipco.rb +66 -0
  26. data/app/models/workarea/payment/capture/zipco.rb +58 -0
  27. data/app/models/workarea/payment/purchase/zipco.rb +66 -0
  28. data/app/models/workarea/payment/refund/zipco.rb +59 -0
  29. data/app/models/workarea/payment/tender/zipco.rb +13 -0
  30. data/app/models/workarea/search/admin/admin.decorator +7 -0
  31. data/app/services/workarea/zipco/checkout.rb +48 -0
  32. data/app/services/workarea/zipco/order.rb +188 -0
  33. data/app/services/workarea/zipco/setup.rb +37 -0
  34. data/app/view_models/workarea/storefront/checkout/payment_view_model.decorator +17 -0
  35. data/app/view_models/workarea/storefront/order_view_model.decorator +11 -0
  36. data/app/view_models/workarea/storefront/zipco_view_model.rb +18 -0
  37. data/app/views/workarea/admin/orders/tenders/_zipco.html.haml +4 -0
  38. data/app/views/workarea/storefront/checkouts/_zipco_payment.html.haml +10 -0
  39. data/app/views/workarea/storefront/order_mailer/tenders/_zipco.html.haml +4 -0
  40. data/app/views/workarea/storefront/order_mailer/tenders/_zipco.text.erb +1 -0
  41. data/app/views/workarea/storefront/orders/_zipco_order_message.html.haml +2 -0
  42. data/app/views/workarea/storefront/orders/tenders/_zipco.html.haml +6 -0
  43. data/app/views/workarea/storefront/zipco/_zipco_tagline.html.haml +4 -0
  44. data/app/views/workarea/storefront/zipco_landing/show.html.haml +4 -0
  45. data/bin/rails +25 -0
  46. data/config/initializers/appends.rb +24 -0
  47. data/config/initializers/workarea.rb +15 -0
  48. data/config/locales/en.yml +38 -0
  49. data/config/routes.rb +5 -0
  50. data/lib/workarea/zipco.rb +48 -0
  51. data/lib/workarea/zipco/bogus_gateway.rb +160 -0
  52. data/lib/workarea/zipco/engine.rb +10 -0
  53. data/lib/workarea/zipco/gateway.rb +113 -0
  54. data/lib/workarea/zipco/response.rb +29 -0
  55. data/lib/workarea/zipco/version.rb +5 -0
  56. data/test/dummy/.ruby-version +1 -0
  57. data/test/dummy/Rakefile +6 -0
  58. data/test/dummy/app/assets/config/manifest.js +3 -0
  59. data/test/dummy/app/assets/images/.keep +0 -0
  60. data/test/dummy/app/assets/javascripts/application.js +14 -0
  61. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  62. data/test/dummy/app/controllers/application_controller.rb +2 -0
  63. data/test/dummy/app/controllers/concerns/.keep +0 -0
  64. data/test/dummy/app/helpers/application_helper.rb +2 -0
  65. data/test/dummy/app/jobs/application_job.rb +2 -0
  66. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  67. data/test/dummy/app/models/concerns/.keep +0 -0
  68. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  69. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  70. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  71. data/test/dummy/bin/bundle +3 -0
  72. data/test/dummy/bin/rails +4 -0
  73. data/test/dummy/bin/rake +4 -0
  74. data/test/dummy/bin/setup +28 -0
  75. data/test/dummy/bin/update +28 -0
  76. data/test/dummy/bin/yarn +11 -0
  77. data/test/dummy/config.ru +5 -0
  78. data/test/dummy/config/application.rb +34 -0
  79. data/test/dummy/config/boot.rb +5 -0
  80. data/test/dummy/config/environment.rb +5 -0
  81. data/test/dummy/config/environments/development.rb +52 -0
  82. data/test/dummy/config/environments/production.rb +83 -0
  83. data/test/dummy/config/environments/test.rb +45 -0
  84. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  85. data/test/dummy/config/initializers/assets.rb +14 -0
  86. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  87. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  88. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  89. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  90. data/test/dummy/config/initializers/inflections.rb +16 -0
  91. data/test/dummy/config/initializers/mime_types.rb +4 -0
  92. data/test/dummy/config/initializers/workarea.rb +5 -0
  93. data/test/dummy/config/initializers/wrap_parameters.rb +9 -0
  94. data/test/dummy/config/locales/en.yml +33 -0
  95. data/test/dummy/config/puma.rb +34 -0
  96. data/test/dummy/config/routes.rb +5 -0
  97. data/test/dummy/config/spring.rb +6 -0
  98. data/test/dummy/db/seeds.rb +2 -0
  99. data/test/dummy/lib/assets/.keep +0 -0
  100. data/test/dummy/log/.keep +0 -0
  101. data/test/integration/workarea/storefront/zipco_integration_test.rb +250 -0
  102. data/test/models/workarea/order/zipco_queries_test.rb +35 -0
  103. data/test/models/workarea/payment/zipco_payment_integration_test.rb +89 -0
  104. data/test/services/workarea/zipco/checkout_test.rb +43 -0
  105. data/test/services/workarea/zipco/order_test.rb +102 -0
  106. data/test/services/workarea/zipco/setup_test.rb +65 -0
  107. data/test/teaspoon_env.rb +6 -0
  108. data/test/test_helper.rb +10 -0
  109. data/test/view_models/workarea/storefront/zipco_view_model_test.rb +55 -0
  110. data/workarea-zipco.gemspec +19 -0
  111. metadata +167 -0
@@ -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,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,2 @@
1
+ require 'workarea/seeds'
2
+ Workarea::Seeds.run
File without changes
File without changes
@@ -0,0 +1,250 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Storefront
5
+ class ZipcoIntengrationTest < Workarea::IntegrationTest
6
+ setup :set_order_data
7
+
8
+ def set_order_data
9
+ create_tax_category(
10
+ name: 'Sales Tax',
11
+ code: '001',
12
+ rates: [{ percentage: 0.07, country: 'US', region: 'PA' }]
13
+ )
14
+
15
+ product = create_product(
16
+ variants: [{ sku: 'SKU1', regular: 6.to_m, tax_code: '001' }]
17
+ )
18
+
19
+ create_shipping_service(
20
+ carrier: 'UPS',
21
+ name: 'Ground',
22
+ service_code: '03',
23
+ tax_code: '001',
24
+ rates: [{ price: 7.to_m }]
25
+ )
26
+
27
+ post storefront.cart_items_path,
28
+ params: {
29
+ product_id: product.id,
30
+ sku: product.skus.first,
31
+ quantity: 2
32
+ }
33
+
34
+ patch storefront.checkout_addresses_path,
35
+ params: {
36
+ email: 'bcrouse@workarea.com',
37
+ billing_address: {
38
+ first_name: 'Ben',
39
+ last_name: 'Crouse',
40
+ street: '12 N. 3rd St.',
41
+ city: 'Philadelphia',
42
+ region: 'PA',
43
+ postal_code: '19106',
44
+ country: 'US',
45
+ phone_number: '2159251800'
46
+ },
47
+ shipping_address: {
48
+ first_name: 'Ben',
49
+ last_name: 'Crouse',
50
+ street: '22 S. 3rd St.',
51
+ city: 'Philadelphia',
52
+ region: 'PA',
53
+ postal_code: '19106',
54
+ country: 'US',
55
+ phone_number: '2159251800'
56
+ }
57
+ }
58
+ patch storefront.checkout_shipping_path
59
+ end
60
+
61
+ def test_start_adds_a_token_to_payment
62
+ get storefront.start_zipco_path
63
+
64
+ payment = Payment.find(order.id)
65
+ payment.reload
66
+
67
+ assert(payment.zipco.present?)
68
+
69
+ order.reload
70
+
71
+ assert(order.zipco_order_id.present?)
72
+ end
73
+
74
+ def test_start_clears_credit_card
75
+ payment = Payment.find(order.id)
76
+ payment.set_credit_card({
77
+ month: "01",
78
+ year: Time.now.year + 1,
79
+ number: 1,
80
+ cvv: "123"
81
+ })
82
+
83
+ payment.reload
84
+
85
+ get storefront.start_zipco_path
86
+
87
+ payment.reload
88
+ order.reload
89
+
90
+ refute(payment.credit_card.present?)
91
+ assert(payment.zipco.present?)
92
+ assert(order.zipco_order_id.present?)
93
+ end
94
+
95
+ def test_cancel_removes_zipco
96
+ payment = Payment.find(order.id)
97
+
98
+ order.update_attributes(zipco_order_id: '1234')
99
+
100
+ payment.set_zipco(token: '1234')
101
+
102
+ assert(payment.zipco?)
103
+
104
+ get storefront.complete_zipco_path(checkoutId: '1234', result: "cancelled")
105
+ payment.reload
106
+ order.reload
107
+
108
+ refute(payment.zipco?)
109
+ refute(order.zipco_order_id.present?)
110
+ end
111
+
112
+ def test_decline_removes_zipco
113
+ payment = Payment.find(order.id)
114
+
115
+ order.update_attributes(zipco_order_id: '1234')
116
+
117
+ payment.set_zipco(token: '1234')
118
+
119
+ assert(payment.zipco?)
120
+
121
+ get storefront.complete_zipco_path(checkoutId: '1234', result: "declined")
122
+ payment.reload
123
+ order.reload
124
+
125
+ refute(payment.zipco?)
126
+ refute(order.zipco_order_id.present?)
127
+ end
128
+
129
+ def test_placing_order_from_zipco
130
+ payment = Payment.find(order.id)
131
+
132
+ get storefront.start_zipco_path
133
+
134
+ params = { checkoutId: 'co_P9GOgSVE9qMnL0VA6Jy8z6', result: 'approved' }
135
+
136
+ get storefront.complete_zipco_path(params)
137
+
138
+ payment.reload
139
+ order.reload
140
+
141
+
142
+ assert(order.placed?)
143
+
144
+ transactions = payment.tenders.first.transactions
145
+ assert_equal(1, transactions.size)
146
+ assert(transactions.first.success?)
147
+ assert_equal('authorize', transactions.first.action)
148
+ end
149
+
150
+ def test_referred_then_approved_order_from_zipco
151
+ payment = Payment.find(order.id)
152
+
153
+ get storefront.start_zipco_path
154
+
155
+ params = { checkoutId: 'co_P9GOgSVE9qMnL0VA6Jy8z6', result: 'referred' }
156
+
157
+ get storefront.complete_zipco_path(params)
158
+
159
+ payment.reload
160
+ order.reload
161
+
162
+ assert(order.zipco_order_id.present?)
163
+ assert(:zipco_referred, order.status)
164
+ refute(order.placed?)
165
+
166
+ transactions = payment.tenders.first.transactions
167
+ assert_equal(0, transactions.size)
168
+ assert(order.zipco_referred?)
169
+ assert_equal(:pending, payment.status)
170
+
171
+ assert_redirected_to(storefront.checkout_confirmation_path)
172
+
173
+ params = { checkoutId: 'co_P9GOgSVE9qMnL0VA6Jy8z6', result: 'approved' }
174
+
175
+ get storefront.complete_zipco_path(params)
176
+
177
+ payment.reload
178
+ order.reload
179
+ transactions = payment.tenders.first.transactions
180
+
181
+ assert_equal(1, transactions.size)
182
+ assert(order.zipco_order_id.present?)
183
+ assert(order.placed?)
184
+ assert(:authorized, payment.status)
185
+ refute(order.zipco_referred?)
186
+ assert_redirected_to(storefront.checkout_confirmation_path)
187
+ end
188
+
189
+ def test_referred_then_cancelled_order_from_zipco
190
+ payment = Payment.find(order.id)
191
+
192
+ get storefront.start_zipco_path
193
+
194
+ params = { checkoutId: 'co_P9GOgSVE9qMnL0VA6Jy8z6', result: 'referred' }
195
+
196
+ get storefront.complete_zipco_path(params)
197
+
198
+ order.reload
199
+ payment.reload
200
+
201
+ assert(order.zipco_order_id.present?)
202
+ refute(order.placed?)
203
+
204
+ assert(order.zipco_referred?)
205
+ assert_equal(:pending, payment.status)
206
+
207
+ params = { checkoutId: 'co_P9GOgSVE9qMnL0VA6Jy8z6', result: 'declined' }
208
+
209
+ get storefront.complete_zipco_path(params)
210
+
211
+ payment.reload
212
+ order.reload
213
+
214
+ assert_equal(:canceled, order.status)
215
+
216
+ transactions = payment.tenders.first.transactions
217
+ assert(:pending, payment.status)
218
+ assert_equal(0, transactions.size)
219
+ assert_redirected_to(storefront.cart_path)
220
+ end
221
+
222
+ def test_failed_zipco_capture
223
+ payment = Payment.find(order.id)
224
+
225
+ payment.set_zipco(token: 'error_token')
226
+
227
+ params = { token: 'error_token', status: 'SUCCESS' }
228
+
229
+ get storefront.complete_zipco_path(params)
230
+
231
+ payment.reload
232
+ order.reload
233
+
234
+ refute(order.placed?)
235
+ end
236
+
237
+ private
238
+
239
+ def order
240
+ @order ||= Order.first
241
+ end
242
+
243
+ def product
244
+ @product ||= create_product(
245
+ variants: [{ sku: 'SKU1', regular: 6.to_m, tax_code: '001' }]
246
+ )
247
+ end
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Zipco
5
+ class ZipcoQueriesTest < Workarea::TestCase
6
+ attr_reader :email, :user
7
+
8
+ setup :setup_user
9
+
10
+ def setup_user
11
+ @email = 'bcrouse@workarea.com'
12
+ @user = create_user(email: email)
13
+ end
14
+
15
+ def test_referred_orders_do_not_need_reminding
16
+ referred_order = Workarea::Order.create!(email: email, checkout_started_at: 2.hours.ago, items: [{ product_id: '1', sku: 2 }], zipco_referred_at: Time.now)
17
+ results = Workarea::Order.need_reminding.to_a
18
+
19
+ refute_includes(results, referred_order)
20
+ end
21
+
22
+ def test_find_current_by_id_excludes_orders_under_review
23
+ order = create_order(zipco_referred_at: Time.now)
24
+
25
+ result = Workarea::Order.find_current(id: order.id)
26
+ refute result.persisted?
27
+ end
28
+
29
+ def test_find_current_by_user_id_excludes_orders_under_review
30
+ result = Workarea::Order.find_current(user_id: 'foo')
31
+ refute result.persisted?
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,89 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ class ZipcoPaymentIntegrationTest < Workarea::TestCase
5
+ def test_auth_capture
6
+ transaction = tender.build_transaction(action: 'authorize')
7
+ Payment::Purchase::Zipco.new(tender, transaction).complete!
8
+
9
+ assert(transaction.success?)
10
+ transaction.save!
11
+
12
+ assert(tender.token.present?)
13
+
14
+ capture = Payment::Capture.new(payment: payment)
15
+ capture.allocate_amounts!(total: 5.to_m)
16
+ assert(capture.valid?)
17
+ capture.complete!
18
+
19
+ capture_transaction = payment.transactions.detect(&:captures)
20
+ assert(capture_transaction.valid?)
21
+ end
22
+
23
+ def test_auth
24
+ transaction = tender.build_transaction(action: 'authorize')
25
+ Payment::Authorize::Zipco.new(tender, transaction).complete!
26
+ assert(transaction.success?, 'expected transaction to be successful')
27
+ end
28
+
29
+ def test_purchase
30
+ transaction = tender.build_transaction(action: 'purchase')
31
+ Payment::Purchase::Zipco.new(tender, transaction).complete!
32
+ assert(transaction.success?)
33
+ end
34
+
35
+ def test_timeout_auth
36
+ transaction = timeout_tender.build_transaction(action: 'authorize')
37
+ operation = Payment::Authorize::Zipco.new(timeout_tender, transaction)
38
+ operation.complete!
39
+ refute(transaction.success?, 'expected transaction to be a failure')
40
+ end
41
+
42
+ private
43
+
44
+ def payment
45
+ @payment ||=
46
+ begin
47
+ profile = create_payment_profile
48
+ create_payment(
49
+ profile_id: profile.id,
50
+ address: {
51
+ first_name: 'Ben',
52
+ last_name: 'Crouse',
53
+ street: '22 s. 3rd st.',
54
+ city: 'Philadelphia',
55
+ region: 'PA',
56
+ postal_code: '19106',
57
+ country: Country['US']
58
+ }
59
+ )
60
+ end
61
+ end
62
+
63
+ def tender
64
+ @tender ||=
65
+ begin
66
+ payment.set_address(first_name: 'Ben', last_name: 'Crouse')
67
+
68
+ payment.build_zipco(
69
+ token: '12345'
70
+ )
71
+
72
+ payment.zipco
73
+ end
74
+ end
75
+
76
+ def timeout_tender
77
+ @tender ||=
78
+ begin
79
+ payment.set_address(first_name: 'Ben', last_name: 'Crouse')
80
+
81
+ payment.build_zipco(
82
+ token: 'timeout_token'
83
+ )
84
+
85
+ payment.zipco
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,43 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Zipco
5
+ class CheckoutTest < Workarea::TestCase
6
+ setup :set_models
7
+
8
+ def set_models
9
+ @user = create_user
10
+ @product = create_product(variants: [{ sku: 'SKU', regular: 5.to_m }])
11
+ @order = create_order(zipco_order_id: "1234", items: [{ product_id: @product.id, sku: 'SKU' }])
12
+ @checkout = Workarea::Checkout.new(@order, @user)
13
+ end
14
+
15
+ def test_complete_approved
16
+ @checkout.payment.set_zipco(token: "1234")
17
+
18
+ @checkout.steps.each do |step|
19
+ step.any_instance.expects(:complete?).returns(true).at_least_once
20
+ end
21
+ Workarea::Checkout::ShippingOptions.any_instance.expects(:valid?).returns(true)
22
+
23
+ zipco_checkout = Zipco::Checkout.new(@checkout, @user, { result: "approved", checkoutId: "1234" })
24
+ complete = zipco_checkout.complete
25
+
26
+ assert(complete)
27
+ end
28
+
29
+ def test_complete_referred
30
+ @checkout.payment.set_zipco(token: "1234")
31
+
32
+ @checkout.steps.each do |step|
33
+ step.any_instance.expects(:complete?).returns(true).at_least_once
34
+ end
35
+ Workarea::Checkout::ShippingOptions.any_instance.expects(:valid?).returns(true)
36
+
37
+ zipco_checkout = Zipco::Checkout.new(@checkout, @user, { result: "referred", checkoutId: "1234" })
38
+ complete = zipco_checkout.complete
39
+ assert(complete)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,102 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Zipco
5
+ class OrderTest < Workarea::TestCase
6
+ def test_to_h
7
+ create_order_total_discount
8
+ order = create_placed_order
9
+ payment = Workarea::Payment.find(order.id)
10
+
11
+ payment = Workarea::Payment.find(order.id)
12
+ payment.profile.update_attributes!(store_credit: 2.00)
13
+ payment.set_store_credit
14
+ payment.tenders.first.amount = 2.to_m
15
+ payment.save
16
+
17
+ order.reload
18
+ payment.reload
19
+
20
+ order_hash = Workarea::Zipco::Order.new(order).to_h
21
+ items = order_hash[:order][:items]
22
+ assert_equal(5, items.size)
23
+
24
+ assert_equal(8.00, order_hash[:order][:amount].to_f)
25
+
26
+ discount_items = items.select { |i| i[:type] == "discount" }
27
+
28
+ assert_equal(2, discount_items.size)
29
+ discount_prices = discount_items.map { |d| d[:amount] }
30
+ assert(discount_prices.include? -1.0) # order total discount
31
+ assert(discount_prices.include? -2.0) # store credit
32
+
33
+ zipco_order = order_hash[:order]
34
+ assert_equal(order.id, zipco_order[:reference])
35
+ assert_equal("USD", zipco_order[:currency])
36
+
37
+ zipco_shipping = zipco_order[:shipping]
38
+ assert(zipco_shipping.present?)
39
+ assert(zipco_shipping[:address].present?)
40
+
41
+ item = order.items.first
42
+ item.adjust_pricing(
43
+ price: 'item',
44
+ quantity: 1,
45
+ description: "Gift Wrapping",
46
+ calculator: "Workarea::Pricing::Calculators::GiftWrappingCalculator",
47
+ amount: 5.to_m,
48
+ data: {}
49
+ )
50
+
51
+ order_hash = Workarea::Zipco::Order.new(order).to_h
52
+
53
+ gift_wrap_item = order_hash[:order][:items].detect { |i| i[:name] == "Gift Wrapping" }
54
+ assert(gift_wrap_item.present?)
55
+ assert_equal(5.0, gift_wrap_item[:amount])
56
+ end
57
+
58
+ private
59
+ def create_order(overrides = {})
60
+ attributes = {
61
+ id: '1234',
62
+ email: 'bcrouse-new@workarea.com',
63
+ placed_at: Time.current
64
+ }.merge(overrides)
65
+
66
+ shipping_service = create_shipping_service
67
+ product = create_product(variants: [{ sku: 'SKU', regular: 5.to_m }])
68
+
69
+ order = Workarea::Order.new(attributes)
70
+ order.add_item(product_id: product.id, sku: 'SKU', quantity: 2)
71
+
72
+ checkout = Checkout.new(order)
73
+ checkout.update(
74
+ shipping_address: {
75
+ first_name: 'Ben',
76
+ last_name: 'Crouse',
77
+ street: '22 S. 3rd St.',
78
+ street_2: 'Second Floor',
79
+ city: 'Philadelphia',
80
+ region: 'PA',
81
+ postal_code: '19106',
82
+ country: 'US'
83
+ },
84
+ billing_address: {
85
+ first_name: 'Bob',
86
+ last_name: 'Clams',
87
+ street: '12 N. 3rd St.',
88
+ street_2: 'Second Floor',
89
+ city: 'Wilmington',
90
+ region: 'DE',
91
+ postal_code: '18083',
92
+ country: 'US'
93
+ },
94
+ shipping_service: shipping_service.name,
95
+ )
96
+
97
+
98
+ order
99
+ end
100
+ end
101
+ end
102
+ end