solidus_bolt 0.0.1

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 (173) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +41 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.github_changelog_generator +2 -0
  6. data/.gitignore +20 -0
  7. data/.rspec +2 -0
  8. data/.rubocop.yml +11 -0
  9. data/CHANGELOG.md +1 -0
  10. data/Gemfile +33 -0
  11. data/LICENSE +26 -0
  12. data/README.md +175 -0
  13. data/Rakefile +6 -0
  14. data/app/assets/images/bolt_logo_standard.png +0 -0
  15. data/app/assets/javascripts/authorize_account.js +74 -0
  16. data/app/assets/javascripts/solidus_bolt.js +91 -0
  17. data/app/assets/javascripts/spree/backend/solidus_bolt.js +4 -0
  18. data/app/assets/javascripts/spree/frontend/solidus_bolt.js +18 -0
  19. data/app/assets/stylesheets/spree/backend/solidus_bolt.css +4 -0
  20. data/app/assets/stylesheets/spree/frontend/solidus_bolt.css +4 -0
  21. data/app/controllers/solidus_bolt/accounts_controller.rb +17 -0
  22. data/app/controllers/solidus_bolt/base_controller.rb +21 -0
  23. data/app/controllers/solidus_bolt/webhooks_controller.rb +21 -0
  24. data/app/controllers/spree/admin/bolt_webhooks_controller.rb +34 -0
  25. data/app/controllers/spree/admin/bolts_controller.rb +43 -0
  26. data/app/decorators/controllers/solidus_bolt/spree_checkout_controller/add_addresses_to_bolt.rb +23 -0
  27. data/app/decorators/controllers/solidus_bolt/spree_checkout_controller/refresh_bolt_addresses.rb +17 -0
  28. data/app/decorators/controllers/solidus_bolt/spree_checkout_controller/refresh_bolt_payment_source.rb +17 -0
  29. data/app/decorators/models/solidus_bolt/address_decorator.rb +22 -0
  30. data/app/decorators/models/solidus_bolt/log_entry_decorator.rb +11 -0
  31. data/app/decorators/models/solidus_bolt/order_decorator.rb +44 -0
  32. data/app/decorators/models/solidus_bolt/payment_decorator.rb +11 -0
  33. data/app/decorators/omniauth/strategies/bolt_decorator.rb +16 -0
  34. data/app/jobs/solidus_bolt/add_address_job.rb +11 -0
  35. data/app/models/solidus_bolt/bolt_configuration.rb +74 -0
  36. data/app/models/solidus_bolt/gateway.rb +133 -0
  37. data/app/models/solidus_bolt/payment_method.rb +35 -0
  38. data/app/models/solidus_bolt/payment_source.rb +13 -0
  39. data/app/models/solidus_bolt.rb +7 -0
  40. data/app/overrides/spree/shared/_head/add_bolt_embed_script.html.erb.deface +6 -0
  41. data/app/services/solidus_bolt/accounts/add_address_service.rb +55 -0
  42. data/app/services/solidus_bolt/accounts/add_payment_method_service.rb +45 -0
  43. data/app/services/solidus_bolt/accounts/detail_service.rb +38 -0
  44. data/app/services/solidus_bolt/accounts/detect_account_service.rb +34 -0
  45. data/app/services/solidus_bolt/base_service.rb +55 -0
  46. data/app/services/solidus_bolt/oauth/token_service.rb +43 -0
  47. data/app/services/solidus_bolt/payments/capture_sync_service.rb +24 -0
  48. data/app/services/solidus_bolt/payments/credit_sync_service.rb +44 -0
  49. data/app/services/solidus_bolt/payments/void_sync_service.rb +18 -0
  50. data/app/services/solidus_bolt/server_error.rb +6 -0
  51. data/app/services/solidus_bolt/transactions/authorize_service.rb +72 -0
  52. data/app/services/solidus_bolt/transactions/base_service.rb +28 -0
  53. data/app/services/solidus_bolt/transactions/capture_service.rb +46 -0
  54. data/app/services/solidus_bolt/transactions/detail_service.rb +38 -0
  55. data/app/services/solidus_bolt/transactions/refund_service.rb +46 -0
  56. data/app/services/solidus_bolt/transactions/void_service.rb +44 -0
  57. data/app/services/solidus_bolt/users/refresh_access_token_service.rb +44 -0
  58. data/app/services/solidus_bolt/users/sync_addresses_service.rb +49 -0
  59. data/app/services/solidus_bolt/users/sync_payment_sources_service.rb +50 -0
  60. data/app/services/solidus_bolt/webhooks/create_service.rb +52 -0
  61. data/app/views/spree/admin/bolt_webhooks/new.html.erb +22 -0
  62. data/app/views/spree/admin/bolts/_configuration.html.erb +32 -0
  63. data/app/views/spree/admin/bolts/_form.html.erb +29 -0
  64. data/app/views/spree/admin/bolts/edit.html.erb +6 -0
  65. data/app/views/spree/admin/bolts/show.html.erb +21 -0
  66. data/app/views/spree/admin/payments/source_forms/_bolt.html.erb +1 -0
  67. data/app/views/spree/admin/payments/source_views/_bolt.html.erb +2 -0
  68. data/app/views/spree/api/payments/source_views/_bolt.json.jbuilder +4 -0
  69. data/app/views/spree/checkout/existing_payment/_bolt.html.erb +7 -0
  70. data/app/views/spree/checkout/payment/_bolt.html.erb +1 -0
  71. data/app/views/spree/shared/payment/_bolt.html.erb +19 -0
  72. data/app/webhooks/solidus_bolt/handlers/base_handler.rb +27 -0
  73. data/app/webhooks/solidus_bolt/handlers/capture_handler.rb +13 -0
  74. data/app/webhooks/solidus_bolt/handlers/credit_handler.rb +18 -0
  75. data/app/webhooks/solidus_bolt/handlers/void_handler.rb +11 -0
  76. data/app/webhooks/solidus_bolt/sorter.rb +33 -0
  77. data/bin/console +17 -0
  78. data/bin/rails +7 -0
  79. data/bin/rails-engine +13 -0
  80. data/bin/rails-sandbox +16 -0
  81. data/bin/rake +7 -0
  82. data/bin/sandbox +86 -0
  83. data/bin/setup +8 -0
  84. data/config/initializers/menu_items.rb +14 -0
  85. data/config/locales/en.yml +17 -0
  86. data/config/routes.rb +11 -0
  87. data/db/migrate/20220330094232_create_solidus_bolt_payment_sources.rb +16 -0
  88. data/db/migrate/20220413063328_create_solidus_bolt_bolt_configurations.rb +14 -0
  89. data/db/migrate/20220502005041_swap_url_for_env_boolean_in_bolt_configuration.rb +6 -0
  90. data/db/migrate/20220509102309_rework_solidus_bolt_payment_sources.rb +19 -0
  91. data/db/migrate/20220510075227_add_create_bolt_account_to_solidus_bolt_payment_source.rb +5 -0
  92. data/db/migrate/20220519233043_add_user_to_solidus_bolt_payment_source.rb +5 -0
  93. data/db/migrate/20220526005619_remove_user_id_from_solidus_bolt_payment_source.rb +5 -0
  94. data/db/migrate/20220530102107_rename_bolt_configuration_merchant_id_to_division_public_id.rb +5 -0
  95. data/db/migrate/20220531075527_update_bolt_configuration_environment_column_restrictions.rb +6 -0
  96. data/db/seeds.rb +30 -0
  97. data/lib/generators/solidus_bolt/install/install_generator.rb +78 -0
  98. data/lib/generators/solidus_bolt/install/templates/initializer.rb +8 -0
  99. data/lib/solidus_bolt/configuration.rb +19 -0
  100. data/lib/solidus_bolt/engine.rb +62 -0
  101. data/lib/solidus_bolt/testing_support/factories.rb +32 -0
  102. data/lib/solidus_bolt/version.rb +5 -0
  103. data/lib/solidus_bolt.rb +9 -0
  104. data/lib/tasks/db/seed/solidus_bolt.rake +14 -0
  105. data/lib/views/frontend/spree/shared/_login_bar_items.html.erb +18 -0
  106. data/solidus_bolt.gemspec +46 -0
  107. data/spec/decorators/models/solidus_bolt/address_decorator_spec.rb +24 -0
  108. data/spec/decorators/models/solidus_bolt/order_decorator_spec.rb +36 -0
  109. data/spec/decorators/models/solidus_bolt/payment_decorator_spec.rb +30 -0
  110. data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddAddressService/_call/with_correct_access_token/receives_a_successful_response.yml +137 -0
  111. data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddAddressService/_call/with_existing_address/skips_the_add_address_call.yml +82 -0
  112. data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddAddressService/_call/with_wrong_access_token/gives_an_error.yml +55 -0
  113. data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddPaymentMethodService/_call/with_correct_access_token/receives_a_successful_response.yml +186 -0
  114. data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddPaymentMethodService/_call/with_wrong_access_token/gives_an_error.yml +179 -0
  115. data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_DetailService/_call/with_correct_access_token/receives_a_successful_response.yml +55 -0
  116. data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_DetailService/_call/with_wrong_access_token/gives_an_error.yml +55 -0
  117. data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_DetectAccountService/_call/receives_the_correct_response.yml +50 -0
  118. data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_DetectAccountService/_call/returns_status_200.yml +50 -0
  119. data/spec/fixtures/vcr_cassettes/SolidusBolt_Oauth_TokenService/_call/makes_the_API_call.yml +59 -0
  120. data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_AuthorizeService/when_repeat_payment/_call/makes_the_API_call.yml +305 -0
  121. data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_AuthorizeService/with_auto_capture/_call/makes_the_API_call.yml +307 -0
  122. data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_AuthorizeService/without_auto_capture/_call/makes_the_API_call.yml +252 -0
  123. data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_CaptureService/_call/makes_the_API_call.yml +242 -0
  124. data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_DetailService/_call/makes_the_API_call.yml +244 -0
  125. data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_RefundService/_call/makes_the_API_call.yml +296 -0
  126. data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_VoidService/_call/makes_the_API_call.yml +242 -0
  127. data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_VoidService/_call/when_transaction_id_is_missing/makes_the_API_call.yml +242 -0
  128. data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_VoidService/_call/when_transaction_reference_is_missing/makes_the_API_call.yml +242 -0
  129. data/spec/fixtures/vcr_cassettes/SolidusBolt_Users_SyncAddressesService/_call/adds_the_bill_address_to_the_user.yml +165 -0
  130. data/spec/fixtures/vcr_cassettes/SolidusBolt_Users_SyncAddressesService/_call/adds_the_ship_address_to_the_user.yml +165 -0
  131. data/spec/fixtures/vcr_cassettes/SolidusBolt_Users_SyncPaymentSourcesService/_call/creates_a_new_payment_source_with_card_ID.yml +55 -0
  132. data/spec/fixtures/vcr_cassettes/SolidusBolt_Webhooks_CreateService/_call/with_all_event/returns_a_webhook_id.yml +54 -0
  133. data/spec/fixtures/vcr_cassettes/SolidusBolt_Webhooks_CreateService/_call/with_an_event/returns_a_webhook_id.yml +54 -0
  134. data/spec/fixtures/vcr_cassettes/SolidusBolt_Webhooks_CreateService/_call/with_empty_event/raises_a_server_error.yml +57 -0
  135. data/spec/jobs/solidus_bolt/add_address_job_spec.rb +18 -0
  136. data/spec/models/solidus_bolt/bolt_configuration_spec.rb +173 -0
  137. data/spec/models/solidus_bolt/gateway_spec.rb +130 -0
  138. data/spec/models/solidus_bolt/payment_method_spec.rb +21 -0
  139. data/spec/models/solidus_bolt/payment_source_spec.rb +22 -0
  140. data/spec/requests/solidus_bolt/accounts_controller_spec.rb +41 -0
  141. data/spec/requests/solidus_bolt/webhooks_controller_spec.rb +122 -0
  142. data/spec/requests/spree/admin/bolt_spec.rb +71 -0
  143. data/spec/requests/spree/admin/bolt_webhook_spec.rb +35 -0
  144. data/spec/requests/spree/checkout_controller_spec.rb +117 -0
  145. data/spec/services/solidus_bolt/accounts/add_address_service_spec.rb +45 -0
  146. data/spec/services/solidus_bolt/accounts/add_payment_method_service_spec.rb +47 -0
  147. data/spec/services/solidus_bolt/accounts/detail_service_spec.rb +32 -0
  148. data/spec/services/solidus_bolt/accounts/detect_account_service_spec.rb +15 -0
  149. data/spec/services/solidus_bolt/base_service_spec.rb +49 -0
  150. data/spec/services/solidus_bolt/oauth/token_service_spec.rb +15 -0
  151. data/spec/services/solidus_bolt/payments/capture_sync_service_spec.rb +27 -0
  152. data/spec/services/solidus_bolt/payments/credit_sync_service_spec.rb +38 -0
  153. data/spec/services/solidus_bolt/payments/void_sync_service_spec.rb +25 -0
  154. data/spec/services/solidus_bolt/transactions/authorize_service_spec.rb +117 -0
  155. data/spec/services/solidus_bolt/transactions/base_service_spec.rb +38 -0
  156. data/spec/services/solidus_bolt/transactions/capture_service_spec.rb +37 -0
  157. data/spec/services/solidus_bolt/transactions/detail_service_spec.rb +31 -0
  158. data/spec/services/solidus_bolt/transactions/refund_service_spec.rb +42 -0
  159. data/spec/services/solidus_bolt/transactions/void_service_spec.rb +70 -0
  160. data/spec/services/solidus_bolt/users/refresh_access_token_service_spec.rb +45 -0
  161. data/spec/services/solidus_bolt/users/sync_addresses_service_spec.rb +74 -0
  162. data/spec/services/solidus_bolt/users/sync_payment_sources_service_spec.rb +25 -0
  163. data/spec/services/solidus_bolt/webhooks/create_service_spec.rb +33 -0
  164. data/spec/spec_helper.rb +37 -0
  165. data/spec/support/bolt_configuration.rb +26 -0
  166. data/spec/support/bolt_helper.rb +66 -0
  167. data/spec/support/vcr.rb +29 -0
  168. data/spec/webhooks/solidus_bolt/handlers/base_handler_spec.rb +13 -0
  169. data/spec/webhooks/solidus_bolt/handlers/capture_handler_spec.rb +24 -0
  170. data/spec/webhooks/solidus_bolt/handlers/credit_handler_spec.rb +32 -0
  171. data/spec/webhooks/solidus_bolt/handlers/void_handler_spec.rb +19 -0
  172. data/spec/webhooks/solidus_bolt/sorter_spec.rb +39 -0
  173. metadata +492 -0
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusBolt
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ class_option :auto_run_migrations, type: :boolean, default: false
7
+ source_root File.expand_path('templates', __dir__)
8
+
9
+ def install_solidus_social
10
+ if File.exist? 'config/initializers/solidus_social.rb'
11
+ puts 'Skipping solidus_social:install' # rubocop:disable Rails/Output
12
+ else
13
+ say_status :install, 'solidus_social extension'
14
+ solidus_social_install_command = 'bin/rails generate solidus_social:install'
15
+ solidus_social_install_command += ' --auto-run-migrations' if options[:auto_run_migrations]
16
+
17
+ run solidus_social_install_command
18
+ end
19
+ end
20
+
21
+ def copy_initializer
22
+ template 'initializer.rb', 'config/initializers/solidus_bolt.rb'
23
+ end
24
+
25
+ def add_javascripts
26
+ append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/solidus_bolt\n"
27
+ append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_bolt\n"
28
+ end
29
+
30
+ def add_stylesheets
31
+ inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_bolt\n", before: %r{\*/}, verbose: true # rubocop:disable Layout/LineLength
32
+ inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_bolt\n", before: %r{\*/}, verbose: true # rubocop:disable Layout/LineLength
33
+ end
34
+
35
+ def add_migrations
36
+ run 'bin/rails railties:install:migrations FROM=solidus_bolt'
37
+ end
38
+
39
+ def add_bolt_omniauth_provider
40
+ solidus_social_initializer_file = 'config/initializers/solidus_social.rb'
41
+ return if File.readlines(solidus_social_initializer_file).grep(/bolt/).any?
42
+
43
+ matcher = /amazon: {\n\s*api_key:\sENV\['AMAZON_API_KEY'\],\n\s*api_secret:\sENV\['AMAZON_API_SECRET'\],\n\s*}\n\s*}/m # rubocop:disable Layout/LineLength
44
+ a = <<~BOLT_PROVIDER
45
+ amazon: {
46
+ api_key: ENV['AMAZON_API_KEY'],
47
+ api_secret: ENV['AMAZON_API_SECRET'],
48
+ }
49
+ }
50
+
51
+ begin
52
+ config.providers[:bolt] = {
53
+ api_key: SolidusBolt::BoltConfiguration.fetch.publishable_key,
54
+ api_secret: SolidusBolt::BoltConfiguration.fetch.api_key,
55
+ }
56
+ rescue StandardError
57
+ end
58
+ BOLT_PROVIDER
59
+
60
+ gsub_file solidus_social_initializer_file, matcher, a
61
+ end
62
+
63
+ def run_migrations
64
+ run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]')) # rubocop:disable Layout/LineLength
65
+ if run_migrations
66
+ run 'bin/rails db:migrate'
67
+ else
68
+ puts 'Skipping bin/rails db:migrate, don\'t forget to run it!' # rubocop:disable Rails/Output
69
+ end
70
+ end
71
+
72
+ def populate_seed_data
73
+ say_status :loading, 'bolt seed data'
74
+ rake('db:seed:solidus_bolt')
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ SolidusBolt.configure do |config|
4
+ # TODO: Remember to change this with the actual preferences you have implemented!
5
+ # config.sample_preference = 'sample_value'
6
+ end
7
+
8
+ Rails.application.config.assets.precompile += %w(bolt_logo_standard.png)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusBolt
4
+ class Configuration
5
+ attr_accessor :bolt_api_key, :bolt_signing_secret, :bolt_publishable_key
6
+ end
7
+
8
+ class << self
9
+ def configuration
10
+ @configuration ||= Configuration.new
11
+ end
12
+
13
+ alias config configuration
14
+
15
+ def configure
16
+ yield configuration
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_core'
4
+ require 'solidus_support'
5
+
6
+ module SolidusBolt
7
+ class Engine < Rails::Engine
8
+ include SolidusSupport::EngineExtensions
9
+
10
+ isolate_namespace ::Spree
11
+
12
+ engine_name 'solidus_bolt'
13
+
14
+ initializer "solidus_bolt.add_static_preference", after: "spree.register.payment_methods" do |app|
15
+ app.config.spree.payment_methods << SolidusBolt::PaymentMethod
16
+ Spree::Config.static_model_preferences.add(
17
+ SolidusBolt::PaymentMethod,
18
+ 'bolt_credentials',
19
+ bolt_credentials_hash
20
+ )
21
+ Spree::Config.static_model_preferences.add(
22
+ SolidusBolt::PaymentMethod,
23
+ 'bolt_config_credentials',
24
+ bolt_config_credentials_hash
25
+ )
26
+
27
+ Spree::PermittedAttributes.source_attributes.concat(%i[
28
+ card_token card_last4 card_bin card_number card_expiration card_postal_code create_bolt_account
29
+ ])
30
+ end
31
+
32
+ # use rspec for tests
33
+ config.generators do |g|
34
+ g.test_framework :rspec
35
+ end
36
+
37
+ private
38
+
39
+ def bolt_credentials_hash
40
+ {
41
+ bolt_api_key: ENV['BOLT_API_KEY'],
42
+ bolt_signing_secret: ENV['BOLT_SIGNING_SECRET'],
43
+ bolt_publishable_key: ENV['BOLT_PUBLISHABLE_KEY'],
44
+ }
45
+ end
46
+
47
+ def bolt_config_credentials_hash
48
+ begin
49
+ bolt_config = SolidusBolt::BoltConfiguration.fetch
50
+ rescue ActiveRecord::StatementInvalid
51
+ bolt_config = nil
52
+ ensure
53
+ bolt_config_hash = {
54
+ bolt_api_key: bolt_config&.api_key,
55
+ bolt_signing_secret: bolt_config&.signing_secret,
56
+ bolt_publishable_key: bolt_config&.publishable_key,
57
+ }
58
+ end
59
+ bolt_config_hash
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :bolt_configuration, class: SolidusBolt::BoltConfiguration do
5
+ bearer_token { SecureRandom.hex }
6
+ environment { 'sandbox' }
7
+ merchant_public_id { SecureRandom.hex }
8
+ division_public_id { SecureRandom.hex }
9
+ api_key { SecureRandom.hex }
10
+ signing_secret { SecureRandom.hex }
11
+ publishable_key { SecureRandom.hex }
12
+ end
13
+
14
+ factory :bolt_payment_method, class: SolidusBolt::PaymentMethod do
15
+ name { 'Bolt' }
16
+ preference_source { 'bolt_credentials' }
17
+ available_to_admin { true }
18
+ available_to_users { true }
19
+ end
20
+
21
+ factory :bolt_payment_source, class: SolidusBolt::PaymentSource do
22
+ create_bolt_account { false }
23
+ payment_method
24
+ end
25
+
26
+ factory :bolt_payment, class: Spree::Payment do
27
+ association(:payment_method, factory: :bolt_payment_method)
28
+ association(:source, factory: :bolt_payment_source)
29
+ order
30
+ state { 'checkout' }
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusBolt
4
+ VERSION = '0.0.1'
5
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_bolt/configuration'
4
+ require 'solidus_bolt/version'
5
+ require 'solidus_bolt/engine'
6
+ require 'httparty'
7
+ require 'solidus_social'
8
+ require 'omniauth-bolt'
9
+ require 'tweetnacl'
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :db do
4
+ namespace :seed do
5
+ desc 'Loads bolt sample data'
6
+ task solidus_bolt: :environment do
7
+ seed_file = Dir[SolidusBolt::Engine.root.join('db', 'seeds.rb')][0]
8
+ return unless File.exist?(seed_file)
9
+
10
+ puts "Seeding #{seed_file}..."
11
+ load(seed_file)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ <% if spree_current_user %>
2
+ <li><%= link_to t('spree.my_account'), spree.account_path %></li>
3
+ <li><%= link_to t('spree.logout'), spree.logout_path, method: Devise.sign_out_via %></li>
4
+ <% else %>
5
+ <li>
6
+ <div class="bolt-account-sso"></div>
7
+ </li>
8
+ <script>
9
+ function insertButtons() {
10
+ if (typeof BoltAccount === 'undefined') {
11
+ window.setTimeout(insertButtons, 100);
12
+ return;
13
+ }
14
+ BoltAccount.injectButtons();
15
+ }
16
+ insertButtons();
17
+ </script>
18
+ <% end %>
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/solidus_bolt/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'solidus_bolt'
7
+ spec.version = SolidusBolt::VERSION
8
+ spec.authors = ['piyushswain', 'Naokimi', 'DanielePalombo']
9
+ spec.email = 'contact@solidus.io'
10
+
11
+ spec.summary = 'Solidus extension for using Bolt Checkout Service.'
12
+ spec.homepage = 'https://github.com/nebulab/solidus_bolt#readme'
13
+ spec.license = 'Apache-2.0'
14
+
15
+ spec.metadata['homepage_uri'] = spec.homepage
16
+ spec.metadata['source_code_uri'] = 'https://github.com/nebulab/solidus_bolt'
17
+ spec.metadata['changelog_uri'] = 'https://github.com/nebulab/solidus_bolt/blob/master/CHANGELOG.md'
18
+
19
+ spec.required_ruby_version = Gem::Requirement.new('~> 2.5')
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ files = Dir.chdir(__dir__) { `git ls-files -z`.split("\x0") }
24
+
25
+ spec.files = files.grep_v(%r{^(test|spec|features)/})
26
+ spec.test_files = files.grep(%r{^(test|spec|features)/})
27
+ spec.bindir = "exe"
28
+ spec.executables = files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_dependency 'coffee-rails'
32
+ spec.add_dependency 'deface'
33
+ spec.add_dependency 'httparty'
34
+ spec.add_dependency 'omniauth-bolt'
35
+ spec.add_dependency 'rails', ['>0.a', '< 7.a']
36
+ spec.add_dependency 'solidus_auth_devise'
37
+ spec.add_dependency 'solidus_core', ['>= 2.0.0', '< 4']
38
+ spec.add_dependency 'solidus_social'
39
+ spec.add_dependency 'solidus_support', '~> 0.5'
40
+ spec.add_dependency 'tweetnacl'
41
+
42
+ spec.add_development_dependency 'pry'
43
+ spec.add_development_dependency 'solidus_dev_support', '~> 2.5'
44
+ spec.add_development_dependency 'vcr'
45
+ spec.add_development_dependency 'webmock'
46
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusBolt::AddressDecorator do
4
+ let(:address) { create(:address) }
5
+ let(:email) { 'example@gmail.com' }
6
+
7
+ describe '#bolt_address' do
8
+ it 'returns a hash with address values and email' do
9
+ result = {
10
+ street_address1: address.address1,
11
+ street_address2: address.address2,
12
+ locality: address.city,
13
+ region: address.state.abbr,
14
+ postal_code: address.zipcode,
15
+ country_code: address.country.iso,
16
+ first_name: Spree::Address::Name.new(address.name).first_name,
17
+ last_name: Spree::Address::Name.new(address.name).last_name,
18
+ phone: address.phone,
19
+ email: email
20
+ }
21
+ expect(address.bolt_address(email)).to eq(result)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusBolt::OrderDecorator do
4
+ let(:order) { create(:order_with_line_items) }
5
+
6
+ describe '#bolt_cart' do
7
+ it 'returns a hash with line items and price' do
8
+ result = {
9
+ total_amount: (order.total * 100).to_i,
10
+ order_reference: order.number,
11
+ currency: 'USD',
12
+ items: [{
13
+ sku: order.line_items.first.sku,
14
+ name: order.line_items.first.name,
15
+ unit_price: 1000,
16
+ quantity: 1
17
+ }]
18
+ }
19
+ expect(order.bolt_cart).to eq(result)
20
+ end
21
+ end
22
+
23
+ describe '#bolt_user_identifier' do
24
+ it 'returns a hash with email and phone' do
25
+ result = { email: order.email, phone: '555-555-0199' }
26
+ expect(order.bolt_user_identifier).to eq(result)
27
+ end
28
+ end
29
+
30
+ describe '#bolt_user_identity' do
31
+ it 'returns a hash with name' do
32
+ result = { 'first_name': 'John', 'last_name': 'Doe' }
33
+ expect(order.bolt_user_identity).to eq(result)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusBolt::PaymentDecorator do
4
+ describe '#can_void?' do
5
+ [
6
+ 'checkout',
7
+ 'completed',
8
+ 'processing',
9
+ 'failed',
10
+ 'void',
11
+ 'invalid'
12
+ ].each do |state|
13
+ let(:payment) { Spree::Payment.new(state: state) }
14
+
15
+ context "when payment state is #{state}" do
16
+ it 'return false' do
17
+ expect(payment.can_void?).to eq false
18
+ end
19
+ end
20
+ end
21
+
22
+ context "when payment state is pending" do
23
+ let(:payment) { Spree::Payment.new(state: 'pending') }
24
+
25
+ it 'return true' do
26
+ expect(payment.can_void?).to eq true
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,137 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api-sandbox.bolt.com/v1/account
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Authorization:
11
+ - "<BEARER AUTHORIZATION>"
12
+ X-Api-Key:
13
+ - "<API_KEY>"
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Tue, 31 May 2022 01:24:31 GMT
27
+ Content-Type:
28
+ - application/json; charset=UTF-8
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Connection:
32
+ - keep-alive
33
+ Public-Key-Pins-Report-Only:
34
+ - max-age=2592000;pin-sha256="OGAVOYhLZd3ADKYGFZOED1c5m1ObMlRv9PyIWrO4Nd0=";pin-sha256="RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho=";pin-sha256="IXHYSIdST+XY22J5ivybYkntMIfjA5P6pMKX2hWG1BE=";report-uri="https://77aa1bd121ef22d50247a23390ce6cff.report-uri.io/r/default/hpkp/reportOnly"
35
+ Set-Cookie:
36
+ - trk=6ed2577d-8b6e-40d7-b914-5f99f4232557; Path=/; Max-Age=31536000; HttpOnly;
37
+ Secure; SameSite=None
38
+ Strict-Transport-Security:
39
+ - max-age=31536000; includeSubDomains; preload
40
+ X-Bolt-Api-Version:
41
+ - '2022-01-01'
42
+ X-Bolt-Trace-Id:
43
+ - Root=1-62956e4f-1a1d5d9371616b3e0bd6cead
44
+ X-Device-Id:
45
+ - a86166e54134f40be90bf98bdf9f1fcac49d23ac4259202b5038010473c636ba
46
+ X-Envoy-Upstream-Service-Time:
47
+ - '36'
48
+ Server:
49
+ - envoy
50
+ body:
51
+ encoding: UTF-8
52
+ string: '{"profile":{"first_name":"asdasd","last_name":"fsfasdf","email":"paulodalberti@nebulab.com","phone":"","name":"asdasd
53
+ fsfasdf"},"addresses":[{"id":"SAM3dnUUNSbQ","street_address1":"PO Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
54
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com","default":true},{"id":"SA728NNovMq9H","street_address1":"PO
55
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10003","country_code":"US","name":"John
56
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email2@example.com","default":false},{"id":"SAhkRT5iEmfuW","street_address1":"125
57
+ E Anderson St","locality":"Savannah","region":"GA","region_code":"GA","postal_code":"31401","country_code":"US","name":"asdasd
58
+ fsfasdf","first_name":"asdasd","last_name":"fsfasdf","phone_number":"2138739655","email_address":"paulodalberti@nebulab.com","default":false}],"payment_methods":[{"id":"CAmPJ4VxVomvF","type":"card","last4":"1004","billing_address":{"id":"AA3NQrvuvWVH1","street_address1":"PO
59
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
60
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com"},"network":"visa","default":true,"exp_month":5,"exp_year":2023},{"id":"CAenwUpogeBSY","type":"card","last4":"1004","billing_address":{"id":"AA655ttsE5Htm","street_address1":"PO
61
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
62
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA7kkwvW31AoT","type":"card","last4":"1111","billing_address":{"id":"AA2PPbJDDiPtB","street_address1":"PO
63
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
64
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA3TiBuJ4g67n","type":"card","last4":"1004","billing_address":{"id":"AA5cLNYqwZyju","street_address1":"PO
65
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10003","country_code":"US","name":"John
66
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email2@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA3BEgomxDJa5","type":"card","last4":"1004","billing_address":{"id":"AAiTJHw4UuWHZ","street_address1":"PO
67
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10005","country_code":"US","name":"John
68
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email3@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA2pgKkgs8Dos","type":"card","last4":"1004","billing_address":{"id":"AAm26afVomLeX","street_address1":"PO
69
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10003","country_code":"US","name":"John
70
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email2@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA49oJyzVdLpw","type":"card","last4":"1004","billing_address":{"id":"AAixhuCPHkQAK","street_address1":"PO
71
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10005","country_code":"US","name":"John
72
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email3@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA5GPxSBpjzie","type":"card","last4":"1004","billing_address":{"id":"AA4JgwX9yDRUR","street_address1":"PO
73
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
74
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CAhGYDjM3THGj","type":"card","last4":"1004","billing_address":{"id":"AA5h6pHzyG4rq","street_address1":"PO
75
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10003","country_code":"US","name":"John
76
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email2@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CAeHu5S7Yjyek","type":"card","last4":"1004","billing_address":{"id":"AAecNe4HcX5WG","street_address1":"10
77
+ Lovely Street","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
78
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"example@email.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CAeZyt3phevU4","type":"card","last4":"1004","billing_address":{"id":"AAaGXye8QrAc1","street_address1":"10
79
+ Lovely Street","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
80
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"example@email.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CAgP9uNSEZBNL","type":"card","last4":"1111","network":"visa","default":false,"exp_month":4,"exp_year":2098}],"has_bolt_account":true}'
81
+ recorded_at: Tue, 31 May 2022 01:24:31 GMT
82
+ - request:
83
+ method: post
84
+ uri: https://api-sandbox.bolt.com/v1/account/addresses
85
+ body:
86
+ encoding: UTF-8
87
+ string: '{"street_address1":"6420","street_address2":"Northwest","locality":"Herndon","region":"AL","postal_code":"10005","country_code":"US","first_name":"John","last_name":"Von
88
+ Doe","phone":"555-555-0199","email":"email2@example.com"}'
89
+ headers:
90
+ Authorization:
91
+ - "<BEARER AUTHORIZATION>"
92
+ Content-Type:
93
+ - application/json
94
+ X-Api-Key:
95
+ - "<API_KEY>"
96
+ Accept-Encoding:
97
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
98
+ Accept:
99
+ - "*/*"
100
+ User-Agent:
101
+ - Ruby
102
+ response:
103
+ status:
104
+ code: 200
105
+ message: OK
106
+ headers:
107
+ Date:
108
+ - Tue, 31 May 2022 01:24:32 GMT
109
+ Content-Type:
110
+ - application/json; charset=UTF-8
111
+ Content-Length:
112
+ - '320'
113
+ Connection:
114
+ - keep-alive
115
+ Public-Key-Pins-Report-Only:
116
+ - max-age=2592000;pin-sha256="OGAVOYhLZd3ADKYGFZOED1c5m1ObMlRv9PyIWrO4Nd0=";pin-sha256="RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho=";pin-sha256="IXHYSIdST+XY22J5ivybYkntMIfjA5P6pMKX2hWG1BE=";report-uri="https://77aa1bd121ef22d50247a23390ce6cff.report-uri.io/r/default/hpkp/reportOnly"
117
+ Set-Cookie:
118
+ - trk=26fa7207-763a-4620-a372-ac05b017834f; Path=/; Max-Age=31536000; HttpOnly;
119
+ Secure; SameSite=None
120
+ Strict-Transport-Security:
121
+ - max-age=31536000; includeSubDomains; preload
122
+ X-Bolt-Api-Version:
123
+ - '2022-01-01'
124
+ X-Bolt-Trace-Id:
125
+ - Root=1-62956e50-70f9b1fb090f35a065a34527
126
+ X-Device-Id:
127
+ - fa03959d09d885b5e85ab84c0070c6ce61dedeadc49829e6aef673d767a766df
128
+ X-Envoy-Upstream-Service-Time:
129
+ - '64'
130
+ Server:
131
+ - envoy
132
+ body:
133
+ encoding: UTF-8
134
+ string: '{"id":"SAfjEyWzmuxRs","street_address1":"6420","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10005","country_code":"US","name":"John
135
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email2@example.com","default":false}'
136
+ recorded_at: Tue, 31 May 2022 01:24:32 GMT
137
+ recorded_with: VCR 6.1.0
@@ -0,0 +1,82 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api-sandbox.bolt.com/v1/account
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Authorization:
11
+ - "<BEARER AUTHORIZATION>"
12
+ X-Api-Key:
13
+ - "<API_KEY>"
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Tue, 31 May 2022 01:23:36 GMT
27
+ Content-Type:
28
+ - application/json; charset=UTF-8
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Connection:
32
+ - keep-alive
33
+ Public-Key-Pins-Report-Only:
34
+ - max-age=2592000;pin-sha256="OGAVOYhLZd3ADKYGFZOED1c5m1ObMlRv9PyIWrO4Nd0=";pin-sha256="RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho=";pin-sha256="IXHYSIdST+XY22J5ivybYkntMIfjA5P6pMKX2hWG1BE=";report-uri="https://77aa1bd121ef22d50247a23390ce6cff.report-uri.io/r/default/hpkp/reportOnly"
35
+ Set-Cookie:
36
+ - trk=0049c155-2eb5-44fd-9a20-c73a847baa68; Path=/; Max-Age=31536000; HttpOnly;
37
+ Secure; SameSite=None
38
+ Strict-Transport-Security:
39
+ - max-age=31536000; includeSubDomains; preload
40
+ X-Bolt-Api-Version:
41
+ - '2022-01-01'
42
+ X-Bolt-Trace-Id:
43
+ - Root=1-62956e18-5aef499c7a23d91d0b98ba02
44
+ X-Device-Id:
45
+ - ade588f38215c8bd482908a0a3d00e03cfd2c3207c04ea86f1d04a9a83be77a8
46
+ X-Envoy-Upstream-Service-Time:
47
+ - '141'
48
+ Server:
49
+ - envoy
50
+ body:
51
+ encoding: UTF-8
52
+ string: '{"profile":{"first_name":"asdasd","last_name":"fsfasdf","email":"paulodalberti@nebulab.com","phone":"","name":"asdasd
53
+ fsfasdf"},"addresses":[{"id":"SAM3dnUUNSbQ","street_address1":"PO Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
54
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com","default":true},{"id":"SA728NNovMq9H","street_address1":"PO
55
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10003","country_code":"US","name":"John
56
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email2@example.com","default":false},{"id":"SAhkRT5iEmfuW","street_address1":"125
57
+ E Anderson St","locality":"Savannah","region":"GA","region_code":"GA","postal_code":"31401","country_code":"US","name":"asdasd
58
+ fsfasdf","first_name":"asdasd","last_name":"fsfasdf","phone_number":"2138739655","email_address":"paulodalberti@nebulab.com","default":false}],"payment_methods":[{"id":"CAmPJ4VxVomvF","type":"card","last4":"1004","billing_address":{"id":"AA3NQrvuvWVH1","street_address1":"PO
59
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
60
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com"},"network":"visa","default":true,"exp_month":5,"exp_year":2023},{"id":"CAenwUpogeBSY","type":"card","last4":"1004","billing_address":{"id":"AA655ttsE5Htm","street_address1":"PO
61
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
62
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA7kkwvW31AoT","type":"card","last4":"1111","billing_address":{"id":"AA2PPbJDDiPtB","street_address1":"PO
63
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
64
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA3TiBuJ4g67n","type":"card","last4":"1004","billing_address":{"id":"AA5cLNYqwZyju","street_address1":"PO
65
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10003","country_code":"US","name":"John
66
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email2@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA3BEgomxDJa5","type":"card","last4":"1004","billing_address":{"id":"AAiTJHw4UuWHZ","street_address1":"PO
67
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10005","country_code":"US","name":"John
68
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email3@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA2pgKkgs8Dos","type":"card","last4":"1004","billing_address":{"id":"AAm26afVomLeX","street_address1":"PO
69
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10003","country_code":"US","name":"John
70
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email2@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA49oJyzVdLpw","type":"card","last4":"1004","billing_address":{"id":"AAixhuCPHkQAK","street_address1":"PO
71
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10005","country_code":"US","name":"John
72
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email3@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CA5GPxSBpjzie","type":"card","last4":"1004","billing_address":{"id":"AA4JgwX9yDRUR","street_address1":"PO
73
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
74
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email1@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CAhGYDjM3THGj","type":"card","last4":"1004","billing_address":{"id":"AA5h6pHzyG4rq","street_address1":"PO
75
+ Box 1337","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10003","country_code":"US","name":"John
76
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"email2@example.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CAeHu5S7Yjyek","type":"card","last4":"1004","billing_address":{"id":"AAecNe4HcX5WG","street_address1":"10
77
+ Lovely Street","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
78
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"example@email.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CAeZyt3phevU4","type":"card","last4":"1004","billing_address":{"id":"AAaGXye8QrAc1","street_address1":"10
79
+ Lovely Street","street_address2":"Northwest","locality":"Herndon","region":"AL","region_code":"AL","postal_code":"10001","country_code":"US","name":"John
80
+ Von Doe","first_name":"John","last_name":"Von Doe","phone_number":"555-555-0199","email_address":"example@email.com"},"network":"visa","default":false,"exp_month":5,"exp_year":2023},{"id":"CAgP9uNSEZBNL","type":"card","last4":"1111","network":"visa","default":false,"exp_month":4,"exp_year":2098}],"has_bolt_account":true}'
81
+ recorded_at: Tue, 31 May 2022 01:23:36 GMT
82
+ recorded_with: VCR 6.1.0