solidus_afterpay 0.1.0
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 +14 -0
- data/CHANGELOG.md +1 -0
- data/Gemfile +33 -0
- data/LICENSE +202 -0
- data/README.md +175 -0
- data/Rakefile +6 -0
- data/app/assets/javascripts/solidus_afterpay/afterpay_checkout.js +131 -0
- data/app/assets/javascripts/spree/backend/solidus_afterpay.js +2 -0
- data/app/assets/javascripts/spree/frontend/solidus_afterpay.js +4 -0
- data/app/assets/stylesheets/spree/backend/solidus_afterpay.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_afterpay.css +4 -0
- data/app/controllers/solidus_afterpay/base_controller.rb +30 -0
- data/app/controllers/solidus_afterpay/callbacks_controller.rb +71 -0
- data/app/controllers/solidus_afterpay/checkouts_controller.rb +47 -0
- data/app/decorators/controllers/solidus_afterpay/spree/checkout_controller_decorator.rb +13 -0
- data/app/decorators/models/solidus_afterpay/spree/order_decorator.rb +15 -0
- data/app/helpers/solidus_afterpay/afterpay_helper.rb +15 -0
- data/app/models/solidus_afterpay/gateway.rb +157 -0
- data/app/models/solidus_afterpay/order_component_builder.rb +97 -0
- data/app/models/solidus_afterpay/payment_method.rb +56 -0
- data/app/models/solidus_afterpay/payment_source.rb +23 -0
- data/app/models/solidus_afterpay/user_agent_generator.rb +35 -0
- data/app/views/solidus_afterpay/_afterpay_javascript.html.erb +5 -0
- data/app/views/spree/admin/payments/source_forms/_afterpay.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/_afterpay.html.erb +0 -0
- data/app/views/spree/api/payments/source_views/_afterpay.json.jbuilder +3 -0
- data/app/views/spree/checkout/payment/_afterpay.html.erb +9 -0
- data/app/views/spree/shared/_afterpay_messaging.html.erb +13 -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/codecov.yml +2 -0
- data/config/locales/en.yml +12 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20210813142725_create_solidus_afterpay_payment_sources.rb +12 -0
- data/lib/generators/solidus_afterpay/install/install_generator.rb +43 -0
- data/lib/generators/solidus_afterpay/install/templates/initializer.rb +5 -0
- data/lib/solidus_afterpay/configuration.rb +25 -0
- data/lib/solidus_afterpay/engine.rb +25 -0
- data/lib/solidus_afterpay/testing_support/factories.rb +20 -0
- data/lib/solidus_afterpay/version.rb +5 -0
- data/lib/solidus_afterpay.rb +5 -0
- data/solidus_afterpay.gemspec +38 -0
- data/spec/fixtures/vcr_casettes/create_checkout/invalid.yml +65 -0
- data/spec/fixtures/vcr_casettes/create_checkout/valid.yml +64 -0
- data/spec/fixtures/vcr_casettes/credit/invalid.yml +61 -0
- data/spec/fixtures/vcr_casettes/credit/valid.yml +63 -0
- data/spec/fixtures/vcr_casettes/deferred/authorize/declined_payment.yml +120 -0
- data/spec/fixtures/vcr_casettes/deferred/authorize/invalid.yml +61 -0
- data/spec/fixtures/vcr_casettes/deferred/authorize/valid.yml +120 -0
- data/spec/fixtures/vcr_casettes/deferred/capture/invalid.yml +61 -0
- data/spec/fixtures/vcr_casettes/deferred/capture/valid.yml +140 -0
- data/spec/fixtures/vcr_casettes/deferred/void/invalid.yml +61 -0
- data/spec/fixtures/vcr_casettes/deferred/void/valid.yml +137 -0
- data/spec/fixtures/vcr_casettes/find_payment/invalid.yml +61 -0
- data/spec/fixtures/vcr_casettes/find_payment/valid.yml +140 -0
- data/spec/fixtures/vcr_casettes/immediate/capture/declined_payment.yml +120 -0
- data/spec/fixtures/vcr_casettes/immediate/capture/invalid.yml +61 -0
- data/spec/fixtures/vcr_casettes/immediate/capture/valid.yml +134 -0
- data/spec/fixtures/vcr_casettes/retrieve_configuration/valid.yml +67 -0
- data/spec/helpers/solidus_afterpay/afterpay_helper_spec.rb +23 -0
- data/spec/models/solidus_afterpay/gateway_spec.rb +418 -0
- data/spec/models/solidus_afterpay/order_component_builder_spec.rb +137 -0
- data/spec/models/solidus_afterpay/payment_method_spec.rb +143 -0
- data/spec/models/solidus_afterpay/payment_source_spec.rb +61 -0
- data/spec/models/solidus_afterpay/user_agent_generator_spec.rb +22 -0
- data/spec/models/spree/order_spec.rb +158 -0
- data/spec/requests/solidus_afterpay/callbacks_controller_spec.rb +127 -0
- data/spec/requests/solidus_afterpay/checkouts_controller_spec.rb +190 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/auth.rb +15 -0
- data/spec/support/preferences.rb +33 -0
- data/spec/support/vcr.rb +18 -0
- metadata +249 -0
data/Rakefile
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
$(function () {
|
2
|
+
function enableSubmit() {
|
3
|
+
/* If we're using jquery-ujs on the frontend, it will automatically disable
|
4
|
+
* the submit button, but do so in a setTimeout here:
|
5
|
+
* https://github.com/rails/jquery-rails/blob/master/vendor/assets/javascripts/jquery_ujs.js#L517
|
6
|
+
* The only way we can re-enable it is by delaying longer than that timeout
|
7
|
+
* or stopping propagation so their submit handler doesn't run. */
|
8
|
+
if ($.rails && typeof $.rails.enableFormElement !== "undefined") {
|
9
|
+
setTimeout(function () {
|
10
|
+
$.rails.enableFormElement($submitButton);
|
11
|
+
$submitButton
|
12
|
+
.attr("disabled", false)
|
13
|
+
.removeClass("disabled")
|
14
|
+
.addClass("primary");
|
15
|
+
}, 100);
|
16
|
+
} else if (
|
17
|
+
typeof Rails !== "undefined" &&
|
18
|
+
typeof Rails.enableElement !== "undefined"
|
19
|
+
) {
|
20
|
+
/* Indicates that we have rails-ujs instead of jquery-ujs. Rails-ujs was added to rails
|
21
|
+
* core in Rails 5.1.0 */
|
22
|
+
setTimeout(function () {
|
23
|
+
Rails.enableElement($submitButton[0]);
|
24
|
+
$submitButton
|
25
|
+
.attr("disabled", false)
|
26
|
+
.removeClass("disabled")
|
27
|
+
.addClass("primary");
|
28
|
+
}, 100);
|
29
|
+
} else {
|
30
|
+
$submitButton
|
31
|
+
.attr("disabled", false)
|
32
|
+
.removeClass("disabled")
|
33
|
+
.addClass("primary");
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
function disableSubmit() {
|
38
|
+
$submitButton
|
39
|
+
.attr("disabled", true)
|
40
|
+
.removeClass("primary")
|
41
|
+
.addClass("disabled");
|
42
|
+
}
|
43
|
+
|
44
|
+
function addFormHook() {
|
45
|
+
$paymentForm.on("submit", function (event) {
|
46
|
+
var selectedPaymentMethodId = parseInt(
|
47
|
+
$("#payment-method-fields input[type='radio']:checked").val()
|
48
|
+
);
|
49
|
+
|
50
|
+
if (paymentMethodId === selectedPaymentMethodId) {
|
51
|
+
event.preventDefault();
|
52
|
+
disableSubmit();
|
53
|
+
|
54
|
+
Spree.ajax({
|
55
|
+
method: "POST",
|
56
|
+
url: "/solidus_afterpay/checkouts.json",
|
57
|
+
data: {
|
58
|
+
order_number: orderNumber,
|
59
|
+
payment_method_id: paymentMethodId,
|
60
|
+
},
|
61
|
+
})
|
62
|
+
.success(function (response) {
|
63
|
+
onSuccess(response);
|
64
|
+
})
|
65
|
+
.error(function (response) {
|
66
|
+
onError(response);
|
67
|
+
});
|
68
|
+
}
|
69
|
+
});
|
70
|
+
}
|
71
|
+
|
72
|
+
function onSuccess(response) {
|
73
|
+
AfterPay.initialize({ countryCode: "US" });
|
74
|
+
if (popupWindow) {
|
75
|
+
openAfterpayPopup(response);
|
76
|
+
} else {
|
77
|
+
AfterPay.redirect({ token: response.token });
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
function onError(response) {
|
82
|
+
enableSubmit();
|
83
|
+
}
|
84
|
+
|
85
|
+
function openAfterpayPopup(response) {
|
86
|
+
AfterPay.onComplete = function (event) {
|
87
|
+
if (event.data.status == "SUCCESS") {
|
88
|
+
onAfterpaySuccess(event);
|
89
|
+
} else {
|
90
|
+
onAfterpayCancel(event);
|
91
|
+
}
|
92
|
+
};
|
93
|
+
AfterPay.open();
|
94
|
+
AfterPay.transfer({ token: response.token });
|
95
|
+
}
|
96
|
+
|
97
|
+
function onAfterpaySuccess(event) {
|
98
|
+
Spree.ajax({
|
99
|
+
method: "POST",
|
100
|
+
url: "/solidus_afterpay/callbacks/confirm.json",
|
101
|
+
data: {
|
102
|
+
order_number: orderNumber,
|
103
|
+
payment_method_id: paymentMethodId,
|
104
|
+
order_token: event.data.orderToken,
|
105
|
+
},
|
106
|
+
})
|
107
|
+
.success(function (response) {
|
108
|
+
window.location.href = response.redirect_url;
|
109
|
+
})
|
110
|
+
.error(function (response) {
|
111
|
+
enableSubmit();
|
112
|
+
});
|
113
|
+
}
|
114
|
+
|
115
|
+
function onAfterpayCancel(event) {
|
116
|
+
enableSubmit();
|
117
|
+
}
|
118
|
+
|
119
|
+
if ($("#afterpay_checkout_payload").length > 0) {
|
120
|
+
var $paymentForm = $("#checkout_form_payment");
|
121
|
+
var $submitButton = $("input[type='submit']", $paymentForm);
|
122
|
+
|
123
|
+
var paymentMethodId = $("#afterpay_checkout_payload").data(
|
124
|
+
"payment-method-id"
|
125
|
+
);
|
126
|
+
var orderNumber = $("#afterpay_checkout_payload").data("order-number");
|
127
|
+
var popupWindow = $("#afterpay_checkout_payload").data("popup-window");
|
128
|
+
|
129
|
+
addFormHook();
|
130
|
+
}
|
131
|
+
});
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusAfterpay
|
4
|
+
class BaseController < ::Spree::BaseController
|
5
|
+
protect_from_forgery unless: -> { request.format.json? }
|
6
|
+
|
7
|
+
rescue_from ::ActiveRecord::RecordNotFound, with: :resource_not_found
|
8
|
+
rescue_from ::CanCan::AccessDenied, with: :unauthorized
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def order_token
|
13
|
+
cookies.signed[:guest_token]
|
14
|
+
end
|
15
|
+
|
16
|
+
def resource_not_found
|
17
|
+
respond_to do |format|
|
18
|
+
format.html { redirect_to spree.cart_path, notice: I18n.t('solidus_afterpay.resource_not_found') }
|
19
|
+
format.json { render json: { error: I18n.t('solidus_afterpay.resource_not_found') }, status: :not_found }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def unauthorized
|
24
|
+
respond_to do |format|
|
25
|
+
format.html { redirect_to spree.cart_path, notice: I18n.t('solidus_afterpay.unauthorized') }
|
26
|
+
format.json { render json: { error: I18n.t('solidus_afterpay.unauthorized') }, status: :unauthorized }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusAfterpay
|
4
|
+
class CallbacksController < SolidusAfterpay::BaseController
|
5
|
+
before_action :ensure_afterpay_order_token_presence, only: :confirm
|
6
|
+
before_action :ensure_order_not_completed, only: :confirm
|
7
|
+
|
8
|
+
def confirm
|
9
|
+
authorize! :update, order, order_token
|
10
|
+
|
11
|
+
if ::Spree::OrderUpdateAttributes.new(order, update_params, request_env: request.headers.env).apply
|
12
|
+
order.next
|
13
|
+
end
|
14
|
+
|
15
|
+
respond_to do |format|
|
16
|
+
format.html { redirect_to checkout_state_path(order.state) }
|
17
|
+
format.json { render json: { redirect_url: checkout_state_url(order.state) } }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def cancel
|
22
|
+
redirect_to checkout_state_path(order.state)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def update_params
|
28
|
+
{
|
29
|
+
payments_attributes: [{
|
30
|
+
payment_method: payment_method,
|
31
|
+
amount: order.total,
|
32
|
+
source_attributes: {
|
33
|
+
token: afterpay_order_token
|
34
|
+
}
|
35
|
+
}]
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def order
|
40
|
+
@order ||= ::Spree::Order.find_by!(number: params[:order_number])
|
41
|
+
end
|
42
|
+
|
43
|
+
def payment_method
|
44
|
+
@payment_method ||= SolidusAfterpay::PaymentMethod.active.find(params[:payment_method_id])
|
45
|
+
end
|
46
|
+
|
47
|
+
def afterpay_order_token
|
48
|
+
params[:orderToken] || params[:order_token]
|
49
|
+
end
|
50
|
+
|
51
|
+
def ensure_afterpay_order_token_presence
|
52
|
+
return if afterpay_order_token
|
53
|
+
|
54
|
+
respond_to do |format|
|
55
|
+
format.html {
|
56
|
+
redirect_to checkout_state_path(order.state), notice: I18n.t('solidus_afterpay.order_token_not_found')
|
57
|
+
}
|
58
|
+
format.json { render json: { error: I18n.t('solidus_afterpay.order_token_not_found') }, status: :not_found }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def ensure_order_not_completed
|
63
|
+
return unless order.complete?
|
64
|
+
|
65
|
+
respond_to do |format|
|
66
|
+
format.html { redirect_to spree.order_path(order), notice: I18n.t('spree.order_already_completed') }
|
67
|
+
format.json { render json: { error: I18n.t('spree.order_already_completed') }, status: :unprocessable_entity }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusAfterpay
|
4
|
+
class CheckoutsController < SolidusAfterpay.api_base_controller_parent_class
|
5
|
+
def create
|
6
|
+
authorize! :update, order, order_token
|
7
|
+
|
8
|
+
response = payment_method.gateway.create_checkout(
|
9
|
+
order,
|
10
|
+
redirect_confirm_url: redirect_confirm_url,
|
11
|
+
redirect_cancel_url: redirect_cancel_url
|
12
|
+
)
|
13
|
+
|
14
|
+
if response.success?
|
15
|
+
render json: {
|
16
|
+
token: response.params['token'],
|
17
|
+
expires: response.params['expires'],
|
18
|
+
redirectCheckoutUrl: response.params['redirectCheckoutUrl']
|
19
|
+
}, status: :created
|
20
|
+
else
|
21
|
+
render json: { error: response.message, errorCode: response.error_code }, status: :unprocessable_entity
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def order
|
28
|
+
@order ||= ::Spree::Order.find_by!(number: params[:order_number])
|
29
|
+
end
|
30
|
+
|
31
|
+
def payment_method
|
32
|
+
@payment_method ||= SolidusAfterpay::PaymentMethod.active.find(params[:payment_method_id])
|
33
|
+
end
|
34
|
+
|
35
|
+
def redirect_confirm_url
|
36
|
+
params[:redirect_confirm_url] || solidus_afterpay.callbacks_confirm_url(
|
37
|
+
order_number: order.number, payment_method_id: payment_method.id
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def redirect_cancel_url
|
42
|
+
params[:redirect_cancel_url] || solidus_afterpay.callbacks_cancel_url(
|
43
|
+
order_number: order.number, payment_method_id: payment_method.id
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusAfterpay
|
4
|
+
module Spree
|
5
|
+
module CheckoutControllerDecorator
|
6
|
+
def self.prepended(base)
|
7
|
+
base.helper ::SolidusAfterpay::AfterpayHelper
|
8
|
+
end
|
9
|
+
|
10
|
+
::Spree::CheckoutController.prepend(self) if SolidusSupport.frontend_available?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusAfterpay
|
4
|
+
module Spree
|
5
|
+
module OrderDecorator
|
6
|
+
def available_payment_methods
|
7
|
+
@available_payment_methods ||= super.select do |payment_method|
|
8
|
+
!payment_method.respond_to?(:available_for_order?) || payment_method.available_for_order?(self)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
::Spree::Order.prepend self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusAfterpay
|
4
|
+
module AfterpayHelper
|
5
|
+
def include_afterpay_js(test_mode: false)
|
6
|
+
afterpay_js_url = if test_mode
|
7
|
+
'https://portal.sandbox.afterpay.com/afterpay.js'
|
8
|
+
else
|
9
|
+
'https://portal.afterpay.com/afterpay.js'
|
10
|
+
end
|
11
|
+
|
12
|
+
javascript_include_tag afterpay_js_url
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'afterpay'
|
4
|
+
|
5
|
+
module SolidusAfterpay
|
6
|
+
class Gateway
|
7
|
+
VOIDABLE_STATUSES = ['AUTH_APPROVED', 'PARTIALLY_CAPTURED'].freeze
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
::Afterpay.configure do |config|
|
11
|
+
config.merchant_id = options[:merchant_id]
|
12
|
+
config.secret_key = options[:secret_key]
|
13
|
+
config.server = 'https://global-api-sandbox.afterpay.com/' if options[:test_mode]
|
14
|
+
config.user_agent = SolidusAfterpay::UserAgentGenerator.new(merchant_id: options[:merchant_id]).generate
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def authorize(_amount, payment_source, _gateway_options)
|
19
|
+
result = {}
|
20
|
+
|
21
|
+
if payment_source.payment_method.preferred_deferred
|
22
|
+
response = ::Afterpay::API::Payment::Auth.call(
|
23
|
+
payment: ::Afterpay::Components::Payment.new(token: payment_source.token)
|
24
|
+
)
|
25
|
+
result = response.body
|
26
|
+
end
|
27
|
+
|
28
|
+
ActiveMerchant::Billing::Response.new(true, 'Transaction approved', result, authorization: result[:id])
|
29
|
+
rescue ::Afterpay::BaseError => e
|
30
|
+
message = e.message
|
31
|
+
error_code = e.error_code
|
32
|
+
if message == 'Afterpay::PaymentRequiredError'
|
33
|
+
message = I18n.t('solidus_afterpay.payment_declined')
|
34
|
+
error_code = 'payment_declined'
|
35
|
+
end
|
36
|
+
ActiveMerchant::Billing::Response.new(false, message, {}, error_code: error_code)
|
37
|
+
end
|
38
|
+
|
39
|
+
def capture(amount, response_code, gateway_options)
|
40
|
+
payment_method = gateway_options[:originator].payment_method
|
41
|
+
|
42
|
+
response = if payment_method.preferred_deferred
|
43
|
+
deferred_capture(amount, response_code, gateway_options)
|
44
|
+
else
|
45
|
+
immediate_capture(amount, response_code, gateway_options)
|
46
|
+
end
|
47
|
+
result = response.body
|
48
|
+
|
49
|
+
if result.status != 'APPROVED'
|
50
|
+
raise ::Afterpay::BaseError.new('payment_declined'), I18n.t('solidus_afterpay.payment_declined')
|
51
|
+
end
|
52
|
+
|
53
|
+
ActiveMerchant::Billing::Response.new(true, 'Transaction captured', result, authorization: result.id)
|
54
|
+
rescue ::Afterpay::BaseError => e
|
55
|
+
ActiveMerchant::Billing::Response.new(false, e.message, {}, error_code: e.error_code)
|
56
|
+
end
|
57
|
+
|
58
|
+
def purchase(amount, payment_source, gateway_options)
|
59
|
+
result = authorize(amount, payment_source, gateway_options)
|
60
|
+
return result unless result.success?
|
61
|
+
|
62
|
+
capture(amount, result.authorization, gateway_options)
|
63
|
+
end
|
64
|
+
|
65
|
+
def credit(amount, response_code, gateway_options)
|
66
|
+
response = ::Afterpay::API::Payment::Refund.call(
|
67
|
+
order_id: response_code,
|
68
|
+
refund: ::Afterpay::Components::Refund.new(
|
69
|
+
amount: ::Afterpay::Components::Money.new(
|
70
|
+
amount: Money.from_cents(amount).amount.to_s,
|
71
|
+
currency: gateway_options[:originator].payment.currency
|
72
|
+
),
|
73
|
+
merchant_reference: gateway_options[:originator].payment.id
|
74
|
+
)
|
75
|
+
)
|
76
|
+
result = response.body
|
77
|
+
|
78
|
+
ActiveMerchant::Billing::Response.new(true, "Transaction Credited with #{amount}", result,
|
79
|
+
authorization: result.refundId)
|
80
|
+
rescue ::Afterpay::BaseError => e
|
81
|
+
ActiveMerchant::Billing::Response.new(false, e.message, {}, error_code: e.error_code)
|
82
|
+
end
|
83
|
+
|
84
|
+
def void(response_code, gateway_options)
|
85
|
+
payment_method = gateway_options[:originator].payment_method
|
86
|
+
|
87
|
+
unless payment_method.preferred_deferred
|
88
|
+
return ActiveMerchant::Billing::Response.new(false, "Transaction can't be voided", {},
|
89
|
+
error_code: 'void_not_allowed')
|
90
|
+
end
|
91
|
+
|
92
|
+
response = ::Afterpay::API::Payment::Void.call(
|
93
|
+
order_id: response_code,
|
94
|
+
payment: ::Afterpay::Components::Payment.new(
|
95
|
+
amount: ::Afterpay::Components::Money.new(
|
96
|
+
amount: gateway_options[:originator].amount.to_s,
|
97
|
+
currency: gateway_options[:currency]
|
98
|
+
)
|
99
|
+
)
|
100
|
+
)
|
101
|
+
result = response.body
|
102
|
+
|
103
|
+
ActiveMerchant::Billing::Response.new(true, 'Transaction voided', result, authorization: result.id)
|
104
|
+
rescue ::Afterpay::BaseError => e
|
105
|
+
ActiveMerchant::Billing::Response.new(false, e.message, {}, error_code: e.error_code)
|
106
|
+
end
|
107
|
+
|
108
|
+
def create_checkout(order, gateway_options)
|
109
|
+
response = ::Afterpay::API::Order::Create.call(
|
110
|
+
order: SolidusAfterpay::OrderComponentBuilder.new(
|
111
|
+
order: order,
|
112
|
+
redirect_confirm_url: gateway_options[:redirect_confirm_url],
|
113
|
+
redirect_cancel_url: gateway_options[:redirect_cancel_url]
|
114
|
+
).call
|
115
|
+
)
|
116
|
+
result = response.body
|
117
|
+
|
118
|
+
ActiveMerchant::Billing::Response.new(true, 'Checkout created', result)
|
119
|
+
rescue ::Afterpay::BaseError => e
|
120
|
+
ActiveMerchant::Billing::Response.new(false, e.message, {}, error_code: e.error_code)
|
121
|
+
end
|
122
|
+
|
123
|
+
def find_payment(order_id:)
|
124
|
+
::Afterpay::API::Payment::Find.call(order_id: order_id).body
|
125
|
+
rescue ::Afterpay::BaseError
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
|
129
|
+
def retrieve_configuration
|
130
|
+
::Afterpay::API::Configuration::Retrieve.call.body
|
131
|
+
rescue ::Afterpay::BaseError
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def immediate_capture(_amount, _response_code, gateway_options)
|
138
|
+
payment_source = gateway_options[:originator].payment_source
|
139
|
+
|
140
|
+
::Afterpay::API::Payment::Capture.call(
|
141
|
+
payment: ::Afterpay::Components::Payment.new(token: payment_source.token)
|
142
|
+
)
|
143
|
+
end
|
144
|
+
|
145
|
+
def deferred_capture(amount, response_code, gateway_options)
|
146
|
+
::Afterpay::API::Payment::DeferredCapture.call(
|
147
|
+
order_id: response_code,
|
148
|
+
payment: ::Afterpay::Components::Payment.new(
|
149
|
+
amount: ::Afterpay::Components::Money.new(
|
150
|
+
amount: Money.from_cents(amount).amount.to_s,
|
151
|
+
currency: gateway_options[:currency]
|
152
|
+
)
|
153
|
+
)
|
154
|
+
)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|