solidus_afterpay 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|