solidus-adyen 0.1.2
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/.gitignore +26 -0
- data/.rubocop.yml +9 -0
- data/.rubocop_todo.yml +325 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +238 -0
- data/Rakefile +16 -0
- data/app/assets/javascripts/spree/backend/solidus-adyen.js +1 -0
- data/app/assets/javascripts/spree/checkout/payment/adyen.js +10 -0
- data/app/assets/javascripts/spree/frontend/solidus-adyen.js +1 -0
- data/app/assets/stylesheets/spree/backend/solidus-adyen/buttons.scss +15 -0
- data/app/assets/stylesheets/spree/backend/solidus-adyen/communication.scss +121 -0
- data/app/assets/stylesheets/spree/backend/solidus-adyen/variables.scss +4 -0
- data/app/assets/stylesheets/spree/backend/solidus-adyen.css +5 -0
- data/app/assets/stylesheets/spree/frontend/solidus-adyen.css +3 -0
- data/app/controllers/concerns/spree/adyen/admin/refunds_controller.rb +59 -0
- data/app/controllers/spree/adyen/hpps_controller.rb +22 -0
- data/app/controllers/spree/adyen_notifications_controller.rb +34 -0
- data/app/controllers/spree/adyen_redirect_controller.rb +90 -0
- data/app/models/adyen_notification.rb +159 -0
- data/app/models/concerns/spree/adyen/order.rb +11 -0
- data/app/models/concerns/spree/adyen/payment.rb +95 -0
- data/app/models/spree/adyen/hpp_source.rb +101 -0
- data/app/models/spree/adyen/notification_processor.rb +102 -0
- data/app/models/spree/adyen/presenters/communication.rb +31 -0
- data/app/models/spree/adyen/presenters/communications/adyen_notification.rb +26 -0
- data/app/models/spree/adyen/presenters/communications/base.rb +50 -0
- data/app/models/spree/adyen/presenters/communications/hpp_source.rb +31 -0
- data/app/models/spree/adyen/presenters/communications/log_entry.rb +28 -0
- data/app/models/spree/adyen/presenters/communications.rb +9 -0
- data/app/models/spree/gateway/adyen_hpp.rb +95 -0
- data/app/overrides/spree/admin/shared/_order_summary.rb +6 -0
- data/app/views/spree/admin/payments/source_forms/_adyen.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/_adyen.html.erb +14 -0
- data/app/views/spree/adyen/_manual_refund.html.erb +9 -0
- data/app/views/spree/adyen/communication/_communication.html.erb +42 -0
- data/app/views/spree/adyen/hpps/directory.html.erb +10 -0
- data/app/views/spree/checkout/payment/_adyen.html.erb +33 -0
- data/bin/checkout.rb +111 -0
- data/bin/regen.sh +1 -0
- data/config/initializers/solidus_adyen.rb +1 -0
- data/config/locales/en.yml +23 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20131017040945_create_adyen_notifications.rb +29 -0
- data/db/migrate/20150911201942_add_index_adyen_notifications_psp_reference.rb +5 -0
- data/db/migrate/20150914162539_create_spree_adyen_hpp_sources.rb +21 -0
- data/db/migrate/20151007090519_add_days_to_ship_to_config.rb +5 -0
- data/db/migrate/20151020230830_remove_indices_on_adyen_notifications.rb +6 -0
- data/db/migrate/20151106093023_allow_merchant_reference_to_be_null_for_adyen_notification.rb +5 -0
- data/lib/solidus-adyen.rb +1 -0
- data/lib/spree/adyen/engine.rb +32 -0
- data/lib/spree/adyen/form.rb +135 -0
- data/lib/spree/adyen/hpp_check.rb +11 -0
- data/lib/spree/adyen/url.rb +30 -0
- data/lib/spree/adyen/version.rb +5 -0
- data/lib/spree/adyen.rb +6 -0
- data/solidus-adyen.gemspec +51 -0
- data/spec/controllers/concerns/spree/adyen/admin/refunds_controller_spec.rb +76 -0
- data/spec/controllers/spree/adyen/hpps_controller_spec.rb +43 -0
- data/spec/controllers/spree/adyen_notifications_controller_spec.rb +118 -0
- data/spec/controllers/spree/adyen_redirect_controller_spec.rb +154 -0
- data/spec/factories/active_merchant_billing_response.rb +23 -0
- data/spec/factories/adyen_notification.rb +91 -0
- data/spec/factories/spree_adyen_hpp_source.rb +15 -0
- data/spec/factories/spree_gateway_adyen_hpp.rb +23 -0
- data/spec/factories/spree_payment.rb +13 -0
- data/spec/lib/spree/adyen/form_spec.rb +214 -0
- data/spec/models/adyen_notification_spec.rb +86 -0
- data/spec/models/concerns/spree/adyen/order_spec.rb +22 -0
- data/spec/models/concerns/spree/adyen/payment_spec.rb +93 -0
- data/spec/models/spree/adyen/hpp_source_spec.rb +101 -0
- data/spec/models/spree/adyen/notification_processor_spec.rb +205 -0
- data/spec/models/spree/adyen/presenters/communication_spec.rb +62 -0
- data/spec/models/spree/gateway/adyen_hpp_spec.rb +76 -0
- data/spec/spec_helper.rb +65 -0
- data/spec/support/shared_contexts/mock_adyen_api.rb +47 -0
- metadata +463 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# This models the response that is received after a user is redirected from the
|
|
2
|
+
# Adyen Hosted Payment Pages. It's used as the the source for the Spree::Payment
|
|
3
|
+
# and keeps track of the messages received from the notifications end point.
|
|
4
|
+
#
|
|
5
|
+
# Attributes defined are dervived from the docs:
|
|
6
|
+
# https://docs.adyen.com/display/TD/HPP+payment+response
|
|
7
|
+
#
|
|
8
|
+
# Information about when certain action are valid:
|
|
9
|
+
# https://docs.adyen.com/display/TD/HPP+modifications
|
|
10
|
+
module Spree::Adyen
|
|
11
|
+
class HppSource < ::ActiveRecord::Base
|
|
12
|
+
MANUALLY_REFUNDABLE = [
|
|
13
|
+
"directEbanking"
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
PENDING = "PENDING".freeze
|
|
17
|
+
AUTHORISED = "AUTHORISED".freeze
|
|
18
|
+
REFUSED = "REFUSED".freeze
|
|
19
|
+
CANCELLED = "CANCELLED".freeze
|
|
20
|
+
|
|
21
|
+
# support updates from capital-cased responses, which is what adyen gives
|
|
22
|
+
# us
|
|
23
|
+
alias_attribute :authResult, :auth_result
|
|
24
|
+
alias_attribute :pspReference, :psp_reference
|
|
25
|
+
alias_attribute :merchantReference, :merchant_reference
|
|
26
|
+
alias_attribute :skinCode, :skin_code
|
|
27
|
+
alias_attribute :merchantSig, :merchant_sig
|
|
28
|
+
alias_attribute :paymentMethod, :payment_method
|
|
29
|
+
alias_attribute :shopperLocale, :shopper_locale
|
|
30
|
+
alias_attribute :merchantReturnData, :merchant_return_data
|
|
31
|
+
|
|
32
|
+
belongs_to :order, class_name: "Spree::Order",
|
|
33
|
+
primary_key: :number,
|
|
34
|
+
foreign_key: :merchant_reference
|
|
35
|
+
|
|
36
|
+
has_one :payment, class_name: "Spree::Payment", as: :source
|
|
37
|
+
|
|
38
|
+
# FIXME should change this to find the auth notification by order number,
|
|
39
|
+
# then all notification that have a original ref that matches it's psp
|
|
40
|
+
has_many :notifications,
|
|
41
|
+
class_name: "AdyenNotification",
|
|
42
|
+
foreign_key: :merchant_reference,
|
|
43
|
+
primary_key: :merchant_reference
|
|
44
|
+
|
|
45
|
+
def can_capture? payment
|
|
46
|
+
payment.uncaptured_amount != 0.0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def actions
|
|
50
|
+
if mutable?
|
|
51
|
+
authorised_actions
|
|
52
|
+
else
|
|
53
|
+
[]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def can_cancel? payment
|
|
58
|
+
payment.refunds.empty?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def requires_manual_refund?
|
|
62
|
+
MANUALLY_REFUNDABLE.include?(payment_method)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def authorised?
|
|
66
|
+
# Many banks return pending, this is considered a valid response and
|
|
67
|
+
# the order should proceed.
|
|
68
|
+
[PENDING, AUTHORISED].include? auth_result
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
def mutable?
|
|
73
|
+
!payment.void? && !payment.processing?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# authorised_actions :: [String] | []
|
|
77
|
+
def authorised_actions
|
|
78
|
+
if auth_notification
|
|
79
|
+
auth_notification.
|
|
80
|
+
actions.map(&method(:transform_action))
|
|
81
|
+
|
|
82
|
+
else
|
|
83
|
+
[]
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def transform_action action
|
|
89
|
+
if action == "refund"
|
|
90
|
+
# return credit so that we go to the new refund action
|
|
91
|
+
"credit"
|
|
92
|
+
else
|
|
93
|
+
action
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def auth_notification
|
|
98
|
+
notifications.processed.authorisation.last
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adyen
|
|
3
|
+
class NotificationProcessor
|
|
4
|
+
attr_accessor :notification, :payment
|
|
5
|
+
|
|
6
|
+
def initialize(notification, payment = nil)
|
|
7
|
+
self.notification = notification
|
|
8
|
+
self.payment = payment ? payment : notification.payment
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# for the given payment, process all notifications that are currently
|
|
12
|
+
# unprocessed in the order that they were dispatched.
|
|
13
|
+
def self.process_outstanding!(payment)
|
|
14
|
+
Spree::Payment.transaction do
|
|
15
|
+
payment.
|
|
16
|
+
source.
|
|
17
|
+
notifications(true). # bypass caching
|
|
18
|
+
unprocessed.
|
|
19
|
+
as_dispatched.
|
|
20
|
+
map do |notification|
|
|
21
|
+
new(notification, payment).process!
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# only process the notification if there is a matching payment there's a
|
|
27
|
+
# number of reasons why there may not be a matching payment such as test
|
|
28
|
+
# notifications, reports etc, we just log them and then accept
|
|
29
|
+
def process!
|
|
30
|
+
Spree::Payment.transaction do
|
|
31
|
+
if payment
|
|
32
|
+
if !notification.success?
|
|
33
|
+
handle_failure
|
|
34
|
+
|
|
35
|
+
elsif notification.modification_event?
|
|
36
|
+
handle_modification_event
|
|
37
|
+
|
|
38
|
+
elsif notification.normal_event?
|
|
39
|
+
handle_normal_event
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
return notification
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def handle_failure
|
|
51
|
+
notification.processed!
|
|
52
|
+
# ignore failures if the payment was already completed
|
|
53
|
+
return if payment.completed?
|
|
54
|
+
# might have to do something else on modification events,
|
|
55
|
+
# namely refunds
|
|
56
|
+
payment.failure!
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def handle_modification_event
|
|
60
|
+
if notification.capture?
|
|
61
|
+
notification.processed!
|
|
62
|
+
complete_payment!
|
|
63
|
+
|
|
64
|
+
elsif notification.cancel_or_refund?
|
|
65
|
+
notification.processed!
|
|
66
|
+
payment.void
|
|
67
|
+
|
|
68
|
+
elsif notification.refund?
|
|
69
|
+
payment.refunds.create!(
|
|
70
|
+
amount: notification.value / 100, # cents to dollars
|
|
71
|
+
transaction_id: notification.psp_reference,
|
|
72
|
+
refund_reason_id: ::Spree::RefundReason.first.id # FIXME
|
|
73
|
+
)
|
|
74
|
+
# payment was processing, move back to completed
|
|
75
|
+
payment.complete!
|
|
76
|
+
notification.processed!
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# normal event is defined as just AUTHORISATION
|
|
81
|
+
def handle_normal_event
|
|
82
|
+
if notification.auto_captured?
|
|
83
|
+
complete_payment!
|
|
84
|
+
|
|
85
|
+
else
|
|
86
|
+
payment.capture!
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
notification.processed!
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def complete_payment!
|
|
93
|
+
money = ::Money.new(notification.value, notification.currency)
|
|
94
|
+
|
|
95
|
+
# this is copied from Spree::Payment::Processing#capture
|
|
96
|
+
payment.capture_events.create!(amount: money.to_f)
|
|
97
|
+
payment.update!(amount: payment.captured_amount)
|
|
98
|
+
payment.complete!
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adyen
|
|
3
|
+
module Presenters
|
|
4
|
+
# Factory for creating communication presenters, based on a payment
|
|
5
|
+
# source.
|
|
6
|
+
class Communication < SimpleDelegator
|
|
7
|
+
PRESENTERS = [
|
|
8
|
+
::Spree::Adyen::Presenters::Communications::AdyenNotification,
|
|
9
|
+
::Spree::Adyen::Presenters::Communications::HppSource,
|
|
10
|
+
::Spree::Adyen::Presenters::Communications::LogEntry
|
|
11
|
+
].freeze
|
|
12
|
+
|
|
13
|
+
def self.from_source source
|
|
14
|
+
([source] + source.notifications + source.payment.log_entries).
|
|
15
|
+
sort_by(&:created_at).
|
|
16
|
+
map { |x| build x }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.build object
|
|
20
|
+
presenter_for(object).new(object)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.presenter_for object
|
|
24
|
+
PRESENTERS.detect do |klass|
|
|
25
|
+
klass.applicable? object
|
|
26
|
+
end || fail("Couldn't map to a communication type")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adyen
|
|
3
|
+
module Presenters
|
|
4
|
+
module Communications
|
|
5
|
+
class AdyenNotification <
|
|
6
|
+
::Spree::Adyen::Presenters::Communications::Base
|
|
7
|
+
|
|
8
|
+
def fields
|
|
9
|
+
{ event_code: event_code,
|
|
10
|
+
reason: reason,
|
|
11
|
+
amount: money.format
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def inbound?
|
|
16
|
+
true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.applicable? obj
|
|
20
|
+
obj.is_a? ::AdyenNotification
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adyen
|
|
3
|
+
module Presenters
|
|
4
|
+
module Communications
|
|
5
|
+
# Base presenters for generic server-api communication representation
|
|
6
|
+
#
|
|
7
|
+
# All communication presenters are expected to implement
|
|
8
|
+
# fields
|
|
9
|
+
# success?
|
|
10
|
+
# processed?
|
|
11
|
+
# inbound?
|
|
12
|
+
class Base < SimpleDelegator
|
|
13
|
+
# force to_partial_path to be called on the delegator and not the
|
|
14
|
+
# delgatee
|
|
15
|
+
def to_model
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_partial_path
|
|
20
|
+
"spree/adyen/communication/communication"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def created_at_s
|
|
24
|
+
created_at.strftime "%d %b %H:%M:%S.%4N"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def present_fields
|
|
28
|
+
fields.compact
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def css_class
|
|
32
|
+
[
|
|
33
|
+
success? ? "success" : "failure",
|
|
34
|
+
processed? ? "processed" : "unprocessed",
|
|
35
|
+
inbound? ? "received" : "sent"
|
|
36
|
+
].
|
|
37
|
+
map { |klass| css_prefix klass }.
|
|
38
|
+
join(" ")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def css_prefix klass
|
|
44
|
+
"adyen-comm-" + klass
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adyen
|
|
3
|
+
module Presenters
|
|
4
|
+
module Communications
|
|
5
|
+
class HppSource < ::Spree::Adyen::Presenters::Communications::Base
|
|
6
|
+
def fields
|
|
7
|
+
{ result: auth_result,
|
|
8
|
+
payment_method: payment_method
|
|
9
|
+
}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def success?
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def processed?
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def inbound?
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.applicable? obj
|
|
25
|
+
obj.is_a? Spree::Adyen::HppSource
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adyen
|
|
3
|
+
module Presenters
|
|
4
|
+
module Communications
|
|
5
|
+
class LogEntry < ::Spree::Adyen::Presenters::Communications::Base
|
|
6
|
+
delegate :success?, :message, to: :parsed_details
|
|
7
|
+
|
|
8
|
+
def processed?
|
|
9
|
+
true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def inbound?
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def fields
|
|
17
|
+
{ message: message
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.applicable? obj
|
|
22
|
+
obj.is_a? Spree::LogEntry
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# Gateway for Adyen Hosted Payment Pages solution
|
|
3
|
+
class Gateway::AdyenHPP < Gateway
|
|
4
|
+
preference :skin_code, :string
|
|
5
|
+
preference :shared_secret, :string
|
|
6
|
+
preference :days_to_ship, :integer, default: 1
|
|
7
|
+
preference :api_username, :string
|
|
8
|
+
preference :api_password, :string
|
|
9
|
+
preference :merchant_account, :string
|
|
10
|
+
|
|
11
|
+
def merchant_account
|
|
12
|
+
ENV["ADYEN_MERCHANT_ACCOUNT"] || preferred_merchant_account
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def provider_class
|
|
16
|
+
::Adyen::API
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def provider
|
|
20
|
+
::Adyen.configuration.api_username =
|
|
21
|
+
(ENV["ADYEN_API_USERNAME"] || preferred_api_username)
|
|
22
|
+
::Adyen.configuration.api_password =
|
|
23
|
+
(ENV["ADYEN_API_PASSWORD"] || preferred_api_password)
|
|
24
|
+
::Adyen.configuration.default_api_params[:merchant_account] =
|
|
25
|
+
merchant_account
|
|
26
|
+
|
|
27
|
+
provider_class
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def method_type
|
|
31
|
+
"adyen"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def shared_secret
|
|
35
|
+
ENV["ADYEN_SHARED_SECRET"] || preferred_shared_secret
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def skin_code
|
|
39
|
+
ENV["ADYEN_SKIN_CODE"] || preferred_skin_code
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def ship_before_date
|
|
43
|
+
preferred_days_to_ship.days.from_now
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def authorize(amount, source, gateway_options)
|
|
47
|
+
# to get around the order checking for processed payments we create payments
|
|
48
|
+
# in the checkout state and allow the payment method to attempt to auth
|
|
49
|
+
# them here. We just return a dummy response here because the payment has
|
|
50
|
+
# already been authorized
|
|
51
|
+
ActiveMerchant::Billing::Response.new(true, "successful hpp payment")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def capture(amount, psp_reference, currency:, **_opts)
|
|
55
|
+
value = { currency: currency, value: amount }
|
|
56
|
+
|
|
57
|
+
handle_response(
|
|
58
|
+
provider.capture_payment(psp_reference, value),
|
|
59
|
+
psp_reference)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def cancel(psp_reference, _gateway_options = {})
|
|
63
|
+
handle_response(
|
|
64
|
+
provider.cancel_or_refund_payment(psp_reference),
|
|
65
|
+
psp_reference)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def credit(amount, psp_reference, currency:, **_opts)
|
|
69
|
+
amount = { currency: currency, value: amount }
|
|
70
|
+
|
|
71
|
+
handle_response(
|
|
72
|
+
provider.refund_payment(psp_reference, amount),
|
|
73
|
+
psp_reference)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def handle_response response, original_reference
|
|
79
|
+
ActiveMerchant::Billing::Response.new(
|
|
80
|
+
response.success?,
|
|
81
|
+
message(response),
|
|
82
|
+
{},
|
|
83
|
+
authorization: original_reference
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def message response
|
|
88
|
+
if response.success?
|
|
89
|
+
JSON.pretty_generate(response.params)
|
|
90
|
+
else
|
|
91
|
+
response.fault_message
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Cannot create Hpp payments on the backend.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<% content_for :page_actions do %>
|
|
2
|
+
<li>
|
|
3
|
+
<%=
|
|
4
|
+
link_to "View in Customer Area",
|
|
5
|
+
Spree::Adyen::URL.payment_adyen_customer_area_url(
|
|
6
|
+
merchant_account: payment.payment_method.preferred_merchant_account,
|
|
7
|
+
psp_reference: payment.response_code
|
|
8
|
+
),
|
|
9
|
+
class: "button fa"
|
|
10
|
+
%>
|
|
11
|
+
</li>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<%= render Spree::Adyen::Presenters::Communication.from_source(payment.source) %>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<%= content_tag :div, class: "#{communication.css_class} clearfix" do %>
|
|
2
|
+
<div class="adyen-comm">
|
|
3
|
+
<div class="adyen-comm-body">
|
|
4
|
+
<div class="adyen-comm-icon">
|
|
5
|
+
<% if !communication.processed? %>
|
|
6
|
+
<i
|
|
7
|
+
class="fa fa-warning adyen-comm-icon-unprocessed"
|
|
8
|
+
title="<%= t("solidus-adyen.payment.unprocessed")%>"
|
|
9
|
+
></i>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% if communication.success? %>
|
|
12
|
+
<i
|
|
13
|
+
class="fa fa-check adyen-comm-icon-success"
|
|
14
|
+
title="<%= t("solidus-adyen.payment.success")%>"
|
|
15
|
+
></i>
|
|
16
|
+
<% else %>
|
|
17
|
+
<i
|
|
18
|
+
class="fa fa-times adyen-comm-icon-failure"
|
|
19
|
+
title="<%= t("solidus-adyen.payment.failure")%>"
|
|
20
|
+
></i>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|
|
23
|
+
<div>
|
|
24
|
+
<div class="adyen-comm-content">
|
|
25
|
+
<% communication.present_fields.each do |name, val| %>
|
|
26
|
+
<div class="adyen-comm-content-row">
|
|
27
|
+
<div class="adyen-comm-content-cell">
|
|
28
|
+
<%= t(".#{name}") %>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="adyen-comm-content-cell">
|
|
31
|
+
<%= val %>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
<% end %>
|
|
35
|
+
</div>
|
|
36
|
+
<p class="adyen-comm-timestamp">
|
|
37
|
+
<%= communication.created_at_s %>
|
|
38
|
+
</p>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
<% end %>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<% content_for :head do %>
|
|
2
|
+
<%= javascript_include_tag 'spree/checkout/payment/adyen.js' %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
5
|
+
<p>
|
|
6
|
+
You'll be redirected to Adyen Hosted Payment Pages. After completing the
|
|
7
|
+
payment form you'll be back to the store.
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<%= content_tag :div, "", id: 'adyen-hpp-details', data: {
|
|
11
|
+
url: directory_adyen_hpp_path(
|
|
12
|
+
order_id: @order.id,
|
|
13
|
+
payment_method_id: payment_method.id) } %>
|
|
14
|
+
|
|
15
|
+
<script type="text/javascript">
|
|
16
|
+
$(function() {
|
|
17
|
+
var spreePaymentRadio = $("#checkout_form_payment input:radio")
|
|
18
|
+
|
|
19
|
+
var hideCheckoutButtonForAdyen = function() {
|
|
20
|
+
if ($("#checkout_form_payment input:radio:checked").val() == <%= payment_method.id %>) {
|
|
21
|
+
$("#checkout_form_payment .form-buttons").hide();
|
|
22
|
+
} else {
|
|
23
|
+
$("#checkout_form_payment .form-buttons").show();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
spreePaymentRadio.change(function() {
|
|
28
|
+
hideCheckoutButtonForAdyen();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
hideCheckoutButtonForAdyen();
|
|
32
|
+
});
|
|
33
|
+
</script>
|