solidus_bolt 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +41 -0
- data/.gem_release.yml +5 -0
- data/.github/stale.yml +17 -0
- data/.github_changelog_generator +2 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.rubocop.yml +11 -0
- data/CHANGELOG.md +1 -0
- data/Gemfile +33 -0
- data/LICENSE +26 -0
- data/README.md +175 -0
- data/Rakefile +6 -0
- data/app/assets/images/bolt_logo_standard.png +0 -0
- data/app/assets/javascripts/authorize_account.js +74 -0
- data/app/assets/javascripts/solidus_bolt.js +91 -0
- data/app/assets/javascripts/spree/backend/solidus_bolt.js +4 -0
- data/app/assets/javascripts/spree/frontend/solidus_bolt.js +18 -0
- data/app/assets/stylesheets/spree/backend/solidus_bolt.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_bolt.css +4 -0
- data/app/controllers/solidus_bolt/accounts_controller.rb +17 -0
- data/app/controllers/solidus_bolt/base_controller.rb +21 -0
- data/app/controllers/solidus_bolt/webhooks_controller.rb +21 -0
- data/app/controllers/spree/admin/bolt_webhooks_controller.rb +34 -0
- data/app/controllers/spree/admin/bolts_controller.rb +43 -0
- data/app/decorators/controllers/solidus_bolt/spree_checkout_controller/add_addresses_to_bolt.rb +23 -0
- data/app/decorators/controllers/solidus_bolt/spree_checkout_controller/refresh_bolt_addresses.rb +17 -0
- data/app/decorators/controllers/solidus_bolt/spree_checkout_controller/refresh_bolt_payment_source.rb +17 -0
- data/app/decorators/models/solidus_bolt/address_decorator.rb +22 -0
- data/app/decorators/models/solidus_bolt/log_entry_decorator.rb +11 -0
- data/app/decorators/models/solidus_bolt/order_decorator.rb +44 -0
- data/app/decorators/models/solidus_bolt/payment_decorator.rb +11 -0
- data/app/decorators/omniauth/strategies/bolt_decorator.rb +16 -0
- data/app/jobs/solidus_bolt/add_address_job.rb +11 -0
- data/app/models/solidus_bolt/bolt_configuration.rb +74 -0
- data/app/models/solidus_bolt/gateway.rb +133 -0
- data/app/models/solidus_bolt/payment_method.rb +35 -0
- data/app/models/solidus_bolt/payment_source.rb +13 -0
- data/app/models/solidus_bolt.rb +7 -0
- data/app/overrides/spree/shared/_head/add_bolt_embed_script.html.erb.deface +6 -0
- data/app/services/solidus_bolt/accounts/add_address_service.rb +55 -0
- data/app/services/solidus_bolt/accounts/add_payment_method_service.rb +45 -0
- data/app/services/solidus_bolt/accounts/detail_service.rb +38 -0
- data/app/services/solidus_bolt/accounts/detect_account_service.rb +34 -0
- data/app/services/solidus_bolt/base_service.rb +55 -0
- data/app/services/solidus_bolt/oauth/token_service.rb +43 -0
- data/app/services/solidus_bolt/payments/capture_sync_service.rb +24 -0
- data/app/services/solidus_bolt/payments/credit_sync_service.rb +44 -0
- data/app/services/solidus_bolt/payments/void_sync_service.rb +18 -0
- data/app/services/solidus_bolt/server_error.rb +6 -0
- data/app/services/solidus_bolt/transactions/authorize_service.rb +72 -0
- data/app/services/solidus_bolt/transactions/base_service.rb +28 -0
- data/app/services/solidus_bolt/transactions/capture_service.rb +46 -0
- data/app/services/solidus_bolt/transactions/detail_service.rb +38 -0
- data/app/services/solidus_bolt/transactions/refund_service.rb +46 -0
- data/app/services/solidus_bolt/transactions/void_service.rb +44 -0
- data/app/services/solidus_bolt/users/refresh_access_token_service.rb +44 -0
- data/app/services/solidus_bolt/users/sync_addresses_service.rb +49 -0
- data/app/services/solidus_bolt/users/sync_payment_sources_service.rb +50 -0
- data/app/services/solidus_bolt/webhooks/create_service.rb +52 -0
- data/app/views/spree/admin/bolt_webhooks/new.html.erb +22 -0
- data/app/views/spree/admin/bolts/_configuration.html.erb +32 -0
- data/app/views/spree/admin/bolts/_form.html.erb +29 -0
- data/app/views/spree/admin/bolts/edit.html.erb +6 -0
- data/app/views/spree/admin/bolts/show.html.erb +21 -0
- data/app/views/spree/admin/payments/source_forms/_bolt.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/_bolt.html.erb +2 -0
- data/app/views/spree/api/payments/source_views/_bolt.json.jbuilder +4 -0
- data/app/views/spree/checkout/existing_payment/_bolt.html.erb +7 -0
- data/app/views/spree/checkout/payment/_bolt.html.erb +1 -0
- data/app/views/spree/shared/payment/_bolt.html.erb +19 -0
- data/app/webhooks/solidus_bolt/handlers/base_handler.rb +27 -0
- data/app/webhooks/solidus_bolt/handlers/capture_handler.rb +13 -0
- data/app/webhooks/solidus_bolt/handlers/credit_handler.rb +18 -0
- data/app/webhooks/solidus_bolt/handlers/void_handler.rb +11 -0
- data/app/webhooks/solidus_bolt/sorter.rb +33 -0
- data/bin/console +17 -0
- data/bin/rails +7 -0
- data/bin/rails-engine +13 -0
- data/bin/rails-sandbox +16 -0
- data/bin/rake +7 -0
- data/bin/sandbox +86 -0
- data/bin/setup +8 -0
- data/config/initializers/menu_items.rb +14 -0
- data/config/locales/en.yml +17 -0
- data/config/routes.rb +11 -0
- data/db/migrate/20220330094232_create_solidus_bolt_payment_sources.rb +16 -0
- data/db/migrate/20220413063328_create_solidus_bolt_bolt_configurations.rb +14 -0
- data/db/migrate/20220502005041_swap_url_for_env_boolean_in_bolt_configuration.rb +6 -0
- data/db/migrate/20220509102309_rework_solidus_bolt_payment_sources.rb +19 -0
- data/db/migrate/20220510075227_add_create_bolt_account_to_solidus_bolt_payment_source.rb +5 -0
- data/db/migrate/20220519233043_add_user_to_solidus_bolt_payment_source.rb +5 -0
- data/db/migrate/20220526005619_remove_user_id_from_solidus_bolt_payment_source.rb +5 -0
- data/db/migrate/20220530102107_rename_bolt_configuration_merchant_id_to_division_public_id.rb +5 -0
- data/db/migrate/20220531075527_update_bolt_configuration_environment_column_restrictions.rb +6 -0
- data/db/seeds.rb +30 -0
- data/lib/generators/solidus_bolt/install/install_generator.rb +78 -0
- data/lib/generators/solidus_bolt/install/templates/initializer.rb +8 -0
- data/lib/solidus_bolt/configuration.rb +19 -0
- data/lib/solidus_bolt/engine.rb +62 -0
- data/lib/solidus_bolt/testing_support/factories.rb +32 -0
- data/lib/solidus_bolt/version.rb +5 -0
- data/lib/solidus_bolt.rb +9 -0
- data/lib/tasks/db/seed/solidus_bolt.rake +14 -0
- data/lib/views/frontend/spree/shared/_login_bar_items.html.erb +18 -0
- data/solidus_bolt.gemspec +46 -0
- data/spec/decorators/models/solidus_bolt/address_decorator_spec.rb +24 -0
- data/spec/decorators/models/solidus_bolt/order_decorator_spec.rb +36 -0
- data/spec/decorators/models/solidus_bolt/payment_decorator_spec.rb +30 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddAddressService/_call/with_correct_access_token/receives_a_successful_response.yml +137 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddAddressService/_call/with_existing_address/skips_the_add_address_call.yml +82 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddAddressService/_call/with_wrong_access_token/gives_an_error.yml +55 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddPaymentMethodService/_call/with_correct_access_token/receives_a_successful_response.yml +186 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_AddPaymentMethodService/_call/with_wrong_access_token/gives_an_error.yml +179 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_DetailService/_call/with_correct_access_token/receives_a_successful_response.yml +55 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_DetailService/_call/with_wrong_access_token/gives_an_error.yml +55 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_DetectAccountService/_call/receives_the_correct_response.yml +50 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Accounts_DetectAccountService/_call/returns_status_200.yml +50 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Oauth_TokenService/_call/makes_the_API_call.yml +59 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_AuthorizeService/when_repeat_payment/_call/makes_the_API_call.yml +305 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_AuthorizeService/with_auto_capture/_call/makes_the_API_call.yml +307 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_AuthorizeService/without_auto_capture/_call/makes_the_API_call.yml +252 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_CaptureService/_call/makes_the_API_call.yml +242 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_DetailService/_call/makes_the_API_call.yml +244 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_RefundService/_call/makes_the_API_call.yml +296 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_VoidService/_call/makes_the_API_call.yml +242 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_VoidService/_call/when_transaction_id_is_missing/makes_the_API_call.yml +242 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Transactions_VoidService/_call/when_transaction_reference_is_missing/makes_the_API_call.yml +242 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Users_SyncAddressesService/_call/adds_the_bill_address_to_the_user.yml +165 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Users_SyncAddressesService/_call/adds_the_ship_address_to_the_user.yml +165 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Users_SyncPaymentSourcesService/_call/creates_a_new_payment_source_with_card_ID.yml +55 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Webhooks_CreateService/_call/with_all_event/returns_a_webhook_id.yml +54 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Webhooks_CreateService/_call/with_an_event/returns_a_webhook_id.yml +54 -0
- data/spec/fixtures/vcr_cassettes/SolidusBolt_Webhooks_CreateService/_call/with_empty_event/raises_a_server_error.yml +57 -0
- data/spec/jobs/solidus_bolt/add_address_job_spec.rb +18 -0
- data/spec/models/solidus_bolt/bolt_configuration_spec.rb +173 -0
- data/spec/models/solidus_bolt/gateway_spec.rb +130 -0
- data/spec/models/solidus_bolt/payment_method_spec.rb +21 -0
- data/spec/models/solidus_bolt/payment_source_spec.rb +22 -0
- data/spec/requests/solidus_bolt/accounts_controller_spec.rb +41 -0
- data/spec/requests/solidus_bolt/webhooks_controller_spec.rb +122 -0
- data/spec/requests/spree/admin/bolt_spec.rb +71 -0
- data/spec/requests/spree/admin/bolt_webhook_spec.rb +35 -0
- data/spec/requests/spree/checkout_controller_spec.rb +117 -0
- data/spec/services/solidus_bolt/accounts/add_address_service_spec.rb +45 -0
- data/spec/services/solidus_bolt/accounts/add_payment_method_service_spec.rb +47 -0
- data/spec/services/solidus_bolt/accounts/detail_service_spec.rb +32 -0
- data/spec/services/solidus_bolt/accounts/detect_account_service_spec.rb +15 -0
- data/spec/services/solidus_bolt/base_service_spec.rb +49 -0
- data/spec/services/solidus_bolt/oauth/token_service_spec.rb +15 -0
- data/spec/services/solidus_bolt/payments/capture_sync_service_spec.rb +27 -0
- data/spec/services/solidus_bolt/payments/credit_sync_service_spec.rb +38 -0
- data/spec/services/solidus_bolt/payments/void_sync_service_spec.rb +25 -0
- data/spec/services/solidus_bolt/transactions/authorize_service_spec.rb +117 -0
- data/spec/services/solidus_bolt/transactions/base_service_spec.rb +38 -0
- data/spec/services/solidus_bolt/transactions/capture_service_spec.rb +37 -0
- data/spec/services/solidus_bolt/transactions/detail_service_spec.rb +31 -0
- data/spec/services/solidus_bolt/transactions/refund_service_spec.rb +42 -0
- data/spec/services/solidus_bolt/transactions/void_service_spec.rb +70 -0
- data/spec/services/solidus_bolt/users/refresh_access_token_service_spec.rb +45 -0
- data/spec/services/solidus_bolt/users/sync_addresses_service_spec.rb +74 -0
- data/spec/services/solidus_bolt/users/sync_payment_sources_service_spec.rb +25 -0
- data/spec/services/solidus_bolt/webhooks/create_service_spec.rb +33 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/bolt_configuration.rb +26 -0
- data/spec/support/bolt_helper.rb +66 -0
- data/spec/support/vcr.rb +29 -0
- data/spec/webhooks/solidus_bolt/handlers/base_handler_spec.rb +13 -0
- data/spec/webhooks/solidus_bolt/handlers/capture_handler_spec.rb +24 -0
- data/spec/webhooks/solidus_bolt/handlers/credit_handler_spec.rb +32 -0
- data/spec/webhooks/solidus_bolt/handlers/void_handler_spec.rb +19 -0
- data/spec/webhooks/solidus_bolt/sorter_spec.rb +39 -0
- metadata +492 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
class BaseService
|
5
|
+
def initialize(*)
|
6
|
+
@config = SolidusBolt::BoltConfiguration.fetch
|
7
|
+
end
|
8
|
+
|
9
|
+
def call
|
10
|
+
raise NotImplementedError
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.call(*args)
|
14
|
+
new(*args).call
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def handle_result(result)
|
20
|
+
return result.parsed_response if result.success?
|
21
|
+
|
22
|
+
raise ServerError, error_message(result)
|
23
|
+
end
|
24
|
+
|
25
|
+
def error_message(result)
|
26
|
+
return result['errors'].map { |e| e['message'] }.join(', ') if result['errors']
|
27
|
+
|
28
|
+
"#{result['error']}: #{result['error_description']}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def api_base_url
|
32
|
+
@config.environment_url
|
33
|
+
end
|
34
|
+
|
35
|
+
def api_version
|
36
|
+
'v1'
|
37
|
+
end
|
38
|
+
|
39
|
+
def generate_nonce
|
40
|
+
SecureRandom.hex
|
41
|
+
end
|
42
|
+
|
43
|
+
def authentication_header
|
44
|
+
{ 'X-API-KEY' => @config.api_key }
|
45
|
+
end
|
46
|
+
|
47
|
+
def publishable_key
|
48
|
+
@config.publishable_key
|
49
|
+
end
|
50
|
+
|
51
|
+
def api_key
|
52
|
+
@config.api_key
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Oauth
|
5
|
+
class TokenService < SolidusBolt::BaseService
|
6
|
+
attr_reader :authorization_code, :scope
|
7
|
+
|
8
|
+
def initialize(authorization_code:, scope:)
|
9
|
+
@authorization_code = authorization_code
|
10
|
+
@scope = scope
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
token
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def token
|
21
|
+
options = build_options
|
22
|
+
handle_result(
|
23
|
+
HTTParty.post(
|
24
|
+
"#{api_base_url}/#{api_version}/oauth/token",
|
25
|
+
options
|
26
|
+
)
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_options
|
31
|
+
{
|
32
|
+
body: {
|
33
|
+
grant_type: 'authorization_code',
|
34
|
+
code: authorization_code,
|
35
|
+
scope: scope,
|
36
|
+
client_id: publishable_key,
|
37
|
+
client_secret: api_key
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Payments
|
5
|
+
class CaptureSyncService < SolidusBolt::BaseService
|
6
|
+
attr_reader :payment, :capture_amount
|
7
|
+
|
8
|
+
def initialize(payment:, capture_amount:)
|
9
|
+
@payment = payment
|
10
|
+
@capture_amount = capture_amount
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
return if payment.completed?
|
16
|
+
|
17
|
+
amount = Money.new(capture_amount).to_d
|
18
|
+
|
19
|
+
payment.capture_events.create!(amount: amount)
|
20
|
+
payment.update!(amount: amount, state: 'completed')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Payments
|
5
|
+
class CreditSyncService < BaseService
|
6
|
+
attr_reader :payment, :amount, :transaction_id, :refund_reason, :order
|
7
|
+
|
8
|
+
def initialize(payment:, amount:, transaction_id:)
|
9
|
+
@payment = payment
|
10
|
+
@amount = amount
|
11
|
+
@transaction_id = transaction_id
|
12
|
+
@refund_reason = Spree::RefundReason.return_processing_reason&.id
|
13
|
+
@order = payment.order
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
return if Spree::Refund.find_by(transaction_id: transaction_id)
|
19
|
+
|
20
|
+
create_refund
|
21
|
+
order.recalculate
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def create_refund
|
27
|
+
payload = {
|
28
|
+
payment_id: payment.id,
|
29
|
+
amount: amount.to_f / 100,
|
30
|
+
transaction_id: transaction_id,
|
31
|
+
refund_reason_id: refund_reason
|
32
|
+
}
|
33
|
+
|
34
|
+
if Spree.solidus_gem_version >= Gem::Version.create('3.0')
|
35
|
+
Spree::Refund.create!(payload)
|
36
|
+
else
|
37
|
+
# Skip after_save callbacks that call the Gateway. Callbacks removed from solidus 3.0 up
|
38
|
+
# https://github.com/solidusio/solidus/blob/v2.11/core/app/models/spree/refund.rb#L20-L22
|
39
|
+
Spree::Refund.insert!(payload) # rubocop:disable Rails/SkipsModelValidations
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Payments
|
5
|
+
class VoidSyncService < BaseService
|
6
|
+
attr_reader :payment
|
7
|
+
|
8
|
+
def initialize(payment:)
|
9
|
+
@payment = payment
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
payment.void! unless payment.void?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Transactions
|
5
|
+
class AuthorizeService < SolidusBolt::Transactions::BaseService
|
6
|
+
attr_reader :order, :create_bolt_account, :credit_card, :auto_capture, :repeat
|
7
|
+
|
8
|
+
def initialize(order:, create_bolt_account:, credit_card:, payment_method:, auto_capture: false, repeat: false)
|
9
|
+
@order = order
|
10
|
+
@create_bolt_account = create_bolt_account
|
11
|
+
@credit_card = credit_card
|
12
|
+
@auto_capture = auto_capture
|
13
|
+
@repeat = repeat
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
authorize
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def authorize
|
24
|
+
url = "#{api_base_url}/#{api_version}/merchant/transactions/authorize"
|
25
|
+
handle_result(
|
26
|
+
HTTParty.post(
|
27
|
+
url, headers: headers, body: (repeat ? repeat_authorization_body : new_authorization_body).to_json
|
28
|
+
)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def new_authorization_body
|
33
|
+
body.merge(
|
34
|
+
credit_card: credit_card,
|
35
|
+
division_id: '', # used to be defined, now needs to stay empty for call to work
|
36
|
+
shipping_address: shipping_address,
|
37
|
+
create_bolt_account: create_bolt_account
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def repeat_authorization_body
|
42
|
+
body.merge(
|
43
|
+
credit_card_id: credit_card[:id]
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def body
|
48
|
+
{
|
49
|
+
auto_capture: auto_capture,
|
50
|
+
cart: order.bolt_cart,
|
51
|
+
source: 'direct_payments',
|
52
|
+
user_identifier: order.bolt_user_identifier,
|
53
|
+
user_identity: order.bolt_user_identity
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def shipping_address
|
58
|
+
order.shipping_address.yield_self do |address|
|
59
|
+
address.bolt_address(order.email)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def headers
|
64
|
+
{
|
65
|
+
'Content-Type' => 'application/json',
|
66
|
+
'X-Nonce' => generate_nonce,
|
67
|
+
'X-Publishable-Key' => publishable_key
|
68
|
+
}.merge(authentication_header)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Transactions
|
5
|
+
class BaseService < SolidusBolt::BaseService
|
6
|
+
attr_reader :payment_method
|
7
|
+
|
8
|
+
def initialize(payment_method:, **args)
|
9
|
+
@payment_method = payment_method
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def api_base_url
|
16
|
+
payment_method.preferred_bolt_api_url
|
17
|
+
end
|
18
|
+
|
19
|
+
def authentication_header
|
20
|
+
{ 'X-API-KEY' => payment_method.preferred_bolt_api_key }
|
21
|
+
end
|
22
|
+
|
23
|
+
def publishable_key
|
24
|
+
payment_method.preferred_bolt_publishable_key
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Transactions
|
5
|
+
class CaptureService < SolidusBolt::Transactions::BaseService
|
6
|
+
attr_reader :transaction_reference, :amount, :currency
|
7
|
+
|
8
|
+
def initialize(transaction_reference:, amount:, currency:, payment_method:)
|
9
|
+
@transaction_reference = transaction_reference
|
10
|
+
@amount = amount
|
11
|
+
@currency = currency
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
capture
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def capture
|
22
|
+
options = build_options
|
23
|
+
handle_result(
|
24
|
+
HTTParty.post(
|
25
|
+
"#{api_base_url}/#{api_version}/merchant/transactions/capture",
|
26
|
+
options
|
27
|
+
)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_options
|
32
|
+
{
|
33
|
+
body: {
|
34
|
+
transaction_reference: transaction_reference,
|
35
|
+
amount: amount,
|
36
|
+
currency: currency
|
37
|
+
}.to_json,
|
38
|
+
headers: {
|
39
|
+
'X-Nonce' => generate_nonce,
|
40
|
+
'Content-Type' => 'application/json'
|
41
|
+
}.merge(authentication_header)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Transactions
|
5
|
+
class DetailService < SolidusBolt::Transactions::BaseService
|
6
|
+
attr_reader :transaction_reference
|
7
|
+
|
8
|
+
def initialize(transaction_reference:, payment_method:)
|
9
|
+
@transaction_reference = transaction_reference
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
detail
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def detail
|
20
|
+
options = build_options
|
21
|
+
handle_result(
|
22
|
+
HTTParty.get(
|
23
|
+
"#{api_base_url}/#{api_version}/merchant/transactions/#{transaction_reference}",
|
24
|
+
options
|
25
|
+
)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_options
|
30
|
+
{
|
31
|
+
headers: {
|
32
|
+
'X-Nonce' => generate_nonce
|
33
|
+
}.merge(authentication_header)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Transactions
|
5
|
+
class RefundService < SolidusBolt::Transactions::BaseService
|
6
|
+
attr_reader :transaction_reference, :amount, :currency
|
7
|
+
|
8
|
+
def initialize(transaction_reference:, amount:, currency:, payment_method:)
|
9
|
+
@transaction_reference = transaction_reference
|
10
|
+
@amount = amount
|
11
|
+
@currency = currency
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
refund
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def refund
|
22
|
+
options = build_options
|
23
|
+
handle_result(
|
24
|
+
HTTParty.post(
|
25
|
+
"#{api_base_url}/#{api_version}/merchant/transactions/credit",
|
26
|
+
options
|
27
|
+
)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_options
|
32
|
+
{
|
33
|
+
body: {
|
34
|
+
transaction_reference: transaction_reference,
|
35
|
+
amount: amount,
|
36
|
+
currency: currency
|
37
|
+
}.to_json,
|
38
|
+
headers: {
|
39
|
+
'X-Nonce' => generate_nonce,
|
40
|
+
'Content-Type' => 'application/json'
|
41
|
+
}.merge(authentication_header)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Transactions
|
5
|
+
class VoidService < SolidusBolt::Transactions::BaseService
|
6
|
+
attr_reader :transaction_reference, :transaction_id
|
7
|
+
|
8
|
+
def initialize(payment_method:, transaction_reference: nil, transaction_id: nil)
|
9
|
+
@transaction_reference = transaction_reference
|
10
|
+
@transaction_id = transaction_id
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
void
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def void
|
21
|
+
options = build_options
|
22
|
+
handle_result(
|
23
|
+
HTTParty.post(
|
24
|
+
"#{api_base_url}/#{api_version}/merchant/transactions/void",
|
25
|
+
options
|
26
|
+
)
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_options
|
31
|
+
{
|
32
|
+
body: {
|
33
|
+
transaction_reference: transaction_reference,
|
34
|
+
transaction_id: transaction_id,
|
35
|
+
}.to_json,
|
36
|
+
headers: {
|
37
|
+
'X-Nonce' => generate_nonce,
|
38
|
+
'Content-Type' => 'application/json'
|
39
|
+
}.merge(authentication_header)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Users
|
5
|
+
class RefreshAccessTokenService < SolidusBolt::BaseService
|
6
|
+
attr_reader :session
|
7
|
+
|
8
|
+
def initialize(session:)
|
9
|
+
@session = session
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
return if session[:bolt_access_token].nil?
|
15
|
+
return session[:bolt_access_token] if session[:bolt_expiration_time] >= Time.now.utc
|
16
|
+
|
17
|
+
refresh_access_token
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def refresh_access_token
|
23
|
+
response = handle_result(HTTParty.post("#{api_base_url}/#{api_version}/oauth/token", build_options))
|
24
|
+
|
25
|
+
session[:bolt_expiration_time] = Time.now.utc + response['expires_in']
|
26
|
+
session[:bolt_refresh_token] = response['refresh_token']
|
27
|
+
session[:bolt_refresh_token_scope] = response['refresh_token_scope']
|
28
|
+
session[:bolt_access_token] = response['access_token']
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_options
|
32
|
+
{
|
33
|
+
body: {
|
34
|
+
grant_type: 'refresh_token',
|
35
|
+
refresh_token: session[:bolt_refresh_token],
|
36
|
+
client_id: publishable_key,
|
37
|
+
scope: session[:bolt_refresh_token_scope],
|
38
|
+
client_secret: api_key
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Users
|
5
|
+
class SyncAddressesService < SolidusBolt::BaseService
|
6
|
+
attr_reader :user, :access_token
|
7
|
+
|
8
|
+
def initialize(user:, access_token:)
|
9
|
+
@access_token = access_token
|
10
|
+
@user = user
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
return if user.nil? || access_token.nil?
|
16
|
+
|
17
|
+
bolt_addresses.each do |bolt_address|
|
18
|
+
default = bolt_address['default']
|
19
|
+
address = convert_to_solidus(bolt_address)
|
20
|
+
user.save_in_address_book(address, default, :shipping)
|
21
|
+
user.save_in_address_book(address, default, :billing)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def user_info
|
28
|
+
@user_info ||= Accounts::DetailService.call(access_token: access_token)
|
29
|
+
end
|
30
|
+
|
31
|
+
def bolt_addresses
|
32
|
+
user_info['addresses']
|
33
|
+
end
|
34
|
+
|
35
|
+
def convert_to_solidus(bolt_address)
|
36
|
+
country = Spree::Country.find_by(iso: bolt_address['country_code'])
|
37
|
+
{
|
38
|
+
address1: bolt_address['street_address1'],
|
39
|
+
city: bolt_address['locality'],
|
40
|
+
state: country.states.find_by(abbr: bolt_address['region_code']),
|
41
|
+
zipcode: bolt_address['postal_code'],
|
42
|
+
name: bolt_address['name'],
|
43
|
+
country: country,
|
44
|
+
phone: bolt_address['phone_number'] || user_info['profile']['phone']
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Users
|
5
|
+
class SyncPaymentSourcesService < SolidusBolt::BaseService
|
6
|
+
attr_reader :user, :access_token, :bolt_payment_method
|
7
|
+
|
8
|
+
def initialize(user:, access_token:)
|
9
|
+
@user = user
|
10
|
+
@access_token = access_token
|
11
|
+
@bolt_payment_method = SolidusBolt::PaymentMethod.last
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
return if user.nil? || access_token.nil? || bolt_payment_method.nil?
|
17
|
+
|
18
|
+
payment_methods.each do |payment_method|
|
19
|
+
add_payment_source(payment_method)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def user_info
|
26
|
+
@user_info ||= Accounts::DetailService.call(access_token: access_token)
|
27
|
+
end
|
28
|
+
|
29
|
+
def payment_methods
|
30
|
+
user_info['payment_methods']
|
31
|
+
end
|
32
|
+
|
33
|
+
def spree_wallet
|
34
|
+
@spree_wallet ||= Spree::Wallet.new(user)
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_payment_source(payment_method)
|
38
|
+
# format of card_expiration: '2022-04'
|
39
|
+
card_expiration = "#{payment_method['exp_year']}-#{payment_method['exp_month'].to_s.rjust(2, '0')}"
|
40
|
+
payment_source = SolidusBolt::PaymentSource.find_or_create_by!(
|
41
|
+
payment_method_id: bolt_payment_method.id,
|
42
|
+
card_last4: payment_method['last4'],
|
43
|
+
card_expiration: card_expiration,
|
44
|
+
card_id: payment_method['id']
|
45
|
+
)
|
46
|
+
spree_wallet.add(payment_source)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusBolt
|
4
|
+
module Webhooks
|
5
|
+
class CreateService < SolidusBolt::BaseService
|
6
|
+
attr_reader :division_public_id, :event, :url
|
7
|
+
|
8
|
+
def initialize(event:, url:)
|
9
|
+
@event = event
|
10
|
+
@url = url
|
11
|
+
@division_public_id = SolidusBolt::BoltConfiguration.fetch.division_public_id
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
create
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def create
|
22
|
+
options = build_options
|
23
|
+
handle_result(
|
24
|
+
HTTParty.post(
|
25
|
+
"#{api_base_url}/#{api_version}/webhooks",
|
26
|
+
options
|
27
|
+
)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_options
|
32
|
+
{
|
33
|
+
body: {
|
34
|
+
division_id: division_public_id,
|
35
|
+
url: url
|
36
|
+
}.merge(event_fields).to_json,
|
37
|
+
headers: {
|
38
|
+
'Content-Type' => 'application/json'
|
39
|
+
}.merge(authentication_header)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def event_fields
|
44
|
+
if event == 'all'
|
45
|
+
{ event_group: event }
|
46
|
+
else
|
47
|
+
{ events: [event] }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<% admin_breadcrumb(plural_resource_name(SolidusBolt::BoltConfiguration)) %>
|
2
|
+
|
3
|
+
<%= form_for :bolt_webhook, url: admin_bolt_webhook_path do |f| %>
|
4
|
+
<fieldset class="form-group no-border-bottom no-border-top">
|
5
|
+
<div class="row">
|
6
|
+
<div id="general_fields" class="col-9">
|
7
|
+
<div class="row">
|
8
|
+
<div class="col-12">
|
9
|
+
<%= f.label :event %>
|
10
|
+
<%= f.select :event, SolidusBolt::BoltConfiguration::EVENTS %><br />
|
11
|
+
<%= f.label :webhook_url %>
|
12
|
+
<%= f.text_field :webhook_url, class: 'fullwidth', value: 'https://domain.com/webhooks/bolt' %>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<div class="row p-2 justify-content-center">
|
16
|
+
<%= f.submit 'Create', class: 'btn btn-primary', data: { disable_with: 'Creating..' } %>
|
17
|
+
<%= link_to 'Cancel', admin_bolt_path, class: 'button' %>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
</fieldset>
|
22
|
+
<% end %>
|