adyen 1.6.0 → 2.0.0.pre1
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 +4 -4
- data/.travis.yml +2 -0
- data/CHANGELOG.md +116 -0
- data/CONTRIBUTING.md +84 -0
- data/Gemfile +1 -1
- data/README.md +33 -0
- data/Rakefile +19 -4
- data/adyen.gemspec +7 -5
- data/config.ru +5 -0
- data/lib/adyen.rb +2 -2
- data/lib/adyen/configuration.rb +6 -0
- data/lib/adyen/form.rb +13 -48
- data/lib/adyen/matchers.rb +1 -1
- data/lib/adyen/rest.rb +53 -0
- data/lib/adyen/rest/authorise_payment.rb +148 -0
- data/lib/adyen/rest/client.rb +110 -0
- data/lib/adyen/rest/errors.rb +33 -0
- data/lib/adyen/rest/modify_payment.rb +97 -0
- data/lib/adyen/rest/request.rb +107 -0
- data/lib/adyen/rest/response.rb +59 -0
- data/lib/adyen/util.rb +147 -0
- data/lib/adyen/version.rb +1 -1
- data/test/form_test.rb +17 -10
- data/test/functional/payment_authorisation_api_test.rb +54 -0
- data/test/functional/payment_modification_api_test.rb +57 -0
- data/test/helpers/configure_adyen.rb +5 -0
- data/test/helpers/example_server.rb +105 -0
- data/test/helpers/public/adyen.encrypt.js +679 -0
- data/test/helpers/public/adyen.encrypt.min.js +14 -0
- data/test/helpers/test_cards.rb +20 -0
- data/test/helpers/views/authorized.erb +7 -0
- data/test/helpers/views/hpp.erb +19 -0
- data/test/helpers/views/index.erb +6 -0
- data/test/helpers/views/pay.erb +36 -0
- data/test/helpers/views/redirect_shopper.erb +18 -0
- data/test/integration/hpp_integration_test.rb +52 -0
- data/test/integration/payment_using_3d_secure_integration_test.rb +40 -0
- data/test/integration/payment_with_client_side_encryption_integration_test.rb +26 -0
- data/test/rest_request_test.rb +50 -0
- data/test/rest_response_test.rb +18 -0
- data/test/test_helper.rb +32 -0
- data/test/util_test.rb +77 -0
- metadata +89 -16
- data/README.rdoc +0 -50
- data/lib/adyen/encoding.rb +0 -21
- data/lib/adyen/formatter.rb +0 -33
- data/test/adyen_test.rb +0 -31
data/lib/adyen/matchers.rb
CHANGED
@@ -21,7 +21,7 @@ module Adyen
|
|
21
21
|
|
22
22
|
# Add a check for all the other fields specified
|
23
23
|
checks.each do |key, value|
|
24
|
-
condition = "\n descendant::input[@type='hidden'][@name='#{Adyen::
|
24
|
+
condition = "\n descendant::input[@type='hidden'][@name='#{Adyen::Util.camelize(key)}']"
|
25
25
|
condition << "[@value='#{value}']" unless value == :anything
|
26
26
|
xpath_query << "[#{condition}]"
|
27
27
|
end
|
data/lib/adyen/rest.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'adyen'
|
2
|
+
require 'adyen/rest/client'
|
3
|
+
|
4
|
+
module Adyen
|
5
|
+
|
6
|
+
# The Adyen::REST module allows you to interact with Adyen's REST API.
|
7
|
+
#
|
8
|
+
# The primary method here is {Adyen::REST.session}, which will yield a
|
9
|
+
# {Adyen::REST::Client} which you can use to send API requests.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# Adyen::REST.session do |client|
|
14
|
+
# client.http.read_timeout = 5
|
15
|
+
# response = client.api_request(...)
|
16
|
+
# # ...
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# @see Adyen::REST.session Use Adyen::REST.session to run code against the API.
|
20
|
+
# @see Adyen::REST::Client Adyen::REST::Client implements the actual API calls.
|
21
|
+
module REST
|
22
|
+
|
23
|
+
# Provides a REST API client this is configured using the values in <tt>Adyen.configuration</tt>.
|
24
|
+
# @param options [Hash] (see Adyen::REST::Client#initialize)
|
25
|
+
# @return [Adyen::REST::Client] A configured client instance
|
26
|
+
# @see .session
|
27
|
+
def self.client
|
28
|
+
Adyen::REST::Client.new(
|
29
|
+
Adyen.configuration.environment,
|
30
|
+
Adyen.configuration.api_username,
|
31
|
+
Adyen.configuration.api_password
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Exectutes a session against the Adyen REST API.
|
36
|
+
#
|
37
|
+
# It will use a standard client from {Adyen::REST.client}, or it uses a provided client.
|
38
|
+
# The client will be yielded to the block, and will be closed after the block is finisged
|
39
|
+
#
|
40
|
+
# @param client [Adyen::REST::Client] A custom API client if a default one won't do.
|
41
|
+
# @yield The provided block will be called in which you can interact with the API using
|
42
|
+
# the provided client. The client will be closed after the block returns.
|
43
|
+
# @yieldparam client [Adyen::REST::Client] The REST client to use for the session.
|
44
|
+
# @return [void]
|
45
|
+
# @see Adyen::REST::Client
|
46
|
+
def self.session(client = nil)
|
47
|
+
client ||= self.client
|
48
|
+
yield(client)
|
49
|
+
ensure
|
50
|
+
client.close
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module Adyen
|
2
|
+
module REST
|
3
|
+
|
4
|
+
# This module implements the <b>Payment.authorise</b>, and <b>Payment.authorise3d</b>
|
5
|
+
# API calls, and includes a custom response class to make handling the response easier.
|
6
|
+
module AuthorisePayment
|
7
|
+
|
8
|
+
class Request < Adyen::REST::Request
|
9
|
+
|
10
|
+
def set_amount(currency, value)
|
11
|
+
self['amount'] = { currency: currency, value: value }
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_encrypted_card_data(source)
|
15
|
+
encrypted_json = if source.respond_to?(:params)
|
16
|
+
source.params['adyen-encrypted-data']
|
17
|
+
elsif source.respond_to?(:[]) && source.key?('adyen-encrypted-data')
|
18
|
+
source['adyen-encrypted-data']
|
19
|
+
else
|
20
|
+
source
|
21
|
+
end
|
22
|
+
|
23
|
+
self['additional_data.card.encrypted.json'] = encrypted_json
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_browser_info(request)
|
27
|
+
self['shopper_ip'] = request.ip
|
28
|
+
self['browser_info.accept_header'] = request['Accept'] || "text/html;q=0.9,*/*",
|
29
|
+
self['browser_info.user_agent'] = request.user_agent
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_3d_secure_parameters(request)
|
33
|
+
set_browser_info(request)
|
34
|
+
self['pa_response'] = request.params['PaRes']
|
35
|
+
self['md'] = request.params['MD']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# The Response class implements some extensions for the authorise payment call.
|
40
|
+
# @see Adyen::REST::Response
|
41
|
+
class Response < Adyen::REST::Response
|
42
|
+
|
43
|
+
# Checks whether the authorisation was successful.
|
44
|
+
# @return [Boolean] <tt>true</tt> iff the authorisation was successful, and the
|
45
|
+
# authorised amount can be captured.
|
46
|
+
def authorised?
|
47
|
+
result_code == AUTHORISED
|
48
|
+
end
|
49
|
+
|
50
|
+
alias_method :authorized?, :authorised?
|
51
|
+
|
52
|
+
# Check whether the payment was refused.
|
53
|
+
# @return [Boolean] <tt>true</tt> iff the authorisation was not successful.
|
54
|
+
def refused?
|
55
|
+
result_code == REFUSED
|
56
|
+
end
|
57
|
+
|
58
|
+
# Checks whether the result of the authorization call was RedirectShopper,
|
59
|
+
# which means that the customer has to be redirected away from your site to
|
60
|
+
# complete the 3Dsecure transaction.
|
61
|
+
# @return [Boolean] <tt>true</tt> iff the shopper has to be redirected,
|
62
|
+
# <tt>false</tt> in any other case.
|
63
|
+
def redirect_shopper?
|
64
|
+
result_code == REDIRECT_SHOPPER
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns the result code from the transaction.
|
68
|
+
# @return [String] The result code.
|
69
|
+
# @see #authorised?
|
70
|
+
# @see #refused?
|
71
|
+
# @see #redirect_shopper?
|
72
|
+
def result_code
|
73
|
+
self[:result_code]
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
AUTHORISED = 'Authorised'.freeze
|
79
|
+
REFUSED = 'Refused'.freeze
|
80
|
+
REDIRECT_SHOPPER = 'RedirectShopper'.freeze
|
81
|
+
private_constant :AUTHORISED, :REFUSED, :REDIRECT_SHOPPER
|
82
|
+
end
|
83
|
+
|
84
|
+
# Generates <tt>Payment.authorise</tt> request for Adyen's webservice.
|
85
|
+
# @param (see #authorise_payment)
|
86
|
+
# @return [Adyen::REST::Request] The request to send
|
87
|
+
# @see #authorise_payment
|
88
|
+
def authorise_payment_request(attributes = {})
|
89
|
+
Adyen::REST::AuthorisePayment::Request.new('Payment.authorise', attributes,
|
90
|
+
prefix: 'payment_request',
|
91
|
+
response_class: Adyen::REST::AuthorisePayment::Response,
|
92
|
+
response_options: { prefix: 'payment_result' })
|
93
|
+
end
|
94
|
+
|
95
|
+
# Sends an authorise payment request to Adyen's webservice.
|
96
|
+
# @param attributes [Hash] The attributes to include in the request.
|
97
|
+
# @return [Adyen::REST::AuthorisePayment::Response] The response from Adyen.
|
98
|
+
# The response responds to <tt>.authorised?</tt> to check whether the
|
99
|
+
# authorization was successful.
|
100
|
+
# @see Adyen::REST::AuthorisePayment::Response#authorised?
|
101
|
+
def authorise_payment(attributes)
|
102
|
+
request = authorise_payment_request(attributes)
|
103
|
+
execute_request(request)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Generates a <tt>Payment.authorise3d</tt> request to Adyen's webservice.
|
107
|
+
#
|
108
|
+
# The response differs based on the credit card uses in the transaction.
|
109
|
+
# For some credit cards, an additional offsite step may be required to complete
|
110
|
+
# the transaction. Check <tt>.redirect_shopper?</tt> to see if this is the case.
|
111
|
+
# Other cards are not 3DSecure-enabled, and may immediately authorise the
|
112
|
+
# transaction. Check <tt>.authorised?</tt> to see if this is the case.
|
113
|
+
#
|
114
|
+
# @param attributes [Hash] The attributes to include in the request.
|
115
|
+
# @return [Adyen::REST::AuthorisePayment::Response] The response from Adyen.
|
116
|
+
# @see Adyen::REST::AuthorisePayment::Response#redirect_shopper?
|
117
|
+
# @see Adyen::REST::AuthorisePayment::Response#authorised?
|
118
|
+
def authorise_payment_3dsecure_request(attributes = {})
|
119
|
+
Adyen::REST::AuthorisePayment::Request.new('Payment.authorise3d', attributes,
|
120
|
+
prefix: 'payment_request_3d',
|
121
|
+
response_class: Adyen::REST::AuthorisePayment::Response,
|
122
|
+
response_options: { prefix: 'payment_result' })
|
123
|
+
end
|
124
|
+
|
125
|
+
# Sends a 3Dsecure-enabled authorise payment request to Adyen's webservice.
|
126
|
+
#
|
127
|
+
# The response differs based on the credit card uses in the transaction.
|
128
|
+
# For some credit cards, an additional offsite step may be required to complete
|
129
|
+
# the transaction. Check <tt>.redirect_shopper?</tt> to see if this is the case.
|
130
|
+
# Other cards are not 3DSecure-enabled, and may immediately authorise the
|
131
|
+
# transaction. Check <tt>.authorised?</tt> to see if this is the case.
|
132
|
+
#
|
133
|
+
# @param attributes [Hash] The attributes to include in the request.
|
134
|
+
# @return [Adyen::REST::AuthorisePayment::Response] The response from Adyen.
|
135
|
+
# @see Adyen::REST::AuthorisePayment::Response#redirect_shopper?
|
136
|
+
# @see Adyen::REST::AuthorisePayment::Response#authorised?
|
137
|
+
def authorise_payment_3dsecure(attributes)
|
138
|
+
request = authorise_payment_3dsecure_request(attributes)
|
139
|
+
execute_request(request)
|
140
|
+
end
|
141
|
+
|
142
|
+
alias_method :authorize_payment_request, :authorise_payment_request
|
143
|
+
alias_method :authorize_payment, :authorise_payment
|
144
|
+
alias_method :authorize_payment_3dsecure_request, :authorise_payment_3dsecure_request
|
145
|
+
alias_method :authorize_payment_3dsecure, :authorise_payment_3dsecure
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
require 'adyen/rest/errors'
|
5
|
+
require 'adyen/rest/request'
|
6
|
+
require 'adyen/rest/response'
|
7
|
+
require 'adyen/rest/authorise_payment'
|
8
|
+
require 'adyen/rest/modify_payment'
|
9
|
+
|
10
|
+
module Adyen
|
11
|
+
module REST
|
12
|
+
|
13
|
+
# The Client class acts as a client to Adyen's REST webservice.
|
14
|
+
#
|
15
|
+
# @!attribute environment [r]
|
16
|
+
# The adyen environment to interact with. Either <tt>'live'</tt> or <tt>'test'</tt>.
|
17
|
+
# @return [String]
|
18
|
+
class Client
|
19
|
+
include AuthorisePayment
|
20
|
+
include ModifyPayment
|
21
|
+
|
22
|
+
attr_reader :environment
|
23
|
+
|
24
|
+
# @param environment [String] The Adyen environment to interface with. Either
|
25
|
+
# <tt>'live'</tt> or <tt>'test'</tt>.
|
26
|
+
# @param username [String] The webservice username, e.g. <tt>ws@Company.Account</tt>
|
27
|
+
# @param password [String] The password associated with the username
|
28
|
+
def initialize(environment, username, password)
|
29
|
+
@environment, @username, @password = environment, username, password
|
30
|
+
end
|
31
|
+
|
32
|
+
# Closes the client.
|
33
|
+
#
|
34
|
+
# - This will terminate the HTTP connection.
|
35
|
+
# - After calling this method, the behavior of any further method calls against
|
36
|
+
# this client instance is undefined.
|
37
|
+
#
|
38
|
+
# @return [void]
|
39
|
+
def close
|
40
|
+
@http.finish if @http && @http.started?
|
41
|
+
@http = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# The underlying <tt>Net::HTTP</tt> instance that is used to execute HTTP
|
45
|
+
# request against the API.
|
46
|
+
#
|
47
|
+
# You can use this to set options on the Net::HTTP instance, like <tt>read_timeout</tt>.
|
48
|
+
# Many of these options will only work if you set them before the HTTP connection is
|
49
|
+
# opened, i.e. before doing the first API call.
|
50
|
+
#
|
51
|
+
# @return [Net::HTTP] The underlying Net::HTTP instance the client uses to perform HTTP request.
|
52
|
+
def http
|
53
|
+
@http ||= Net::HTTP.new(endpoint.host, endpoint.port).tap do |http|
|
54
|
+
http.use_ssl = endpoint.scheme == 'https'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Executes an API request, and returns a reponse of the given type.
|
59
|
+
#
|
60
|
+
# @param request [Adyen::REST::Request] The API request to execute.
|
61
|
+
# <tt>validate!</tt> will be called on the this object before the
|
62
|
+
# request is made.
|
63
|
+
# @param response_type [Class] The response type to use. Use either
|
64
|
+
# <tt>Adyen::REST::Response</tt> or a subclass.
|
65
|
+
# @return [Adyen::REST::Response] A response instance of the provided type
|
66
|
+
# @see execute_http_request The <tt>execute_http_request</tt> takes care
|
67
|
+
# of executing the underlying HTTP request.
|
68
|
+
def execute_request(request)
|
69
|
+
request.validate!
|
70
|
+
http_response = execute_http_request(request)
|
71
|
+
request.build_response(http_response)
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
# Executes a HTTP request against Adyen's REST webservice.
|
77
|
+
# @param request [Adyen::REST::Request] The request to execute.
|
78
|
+
# @return [Net::HTTPResponse] The response from the server.
|
79
|
+
# @raise [Adyen::REST::Error] if the HTTP response code was not 200.
|
80
|
+
# @see #http Use the <tt>http</tt> method to set options on the underlying
|
81
|
+
# <tt>Net::HTTP</tt> object, like timeouts.
|
82
|
+
def execute_http_request(request)
|
83
|
+
http_request = Net::HTTP::Post.new(endpoint.path)
|
84
|
+
http_request.basic_auth(@username, @password)
|
85
|
+
http_request.set_form_data(request.form_data)
|
86
|
+
|
87
|
+
case response = http.request(http_request)
|
88
|
+
when Net::HTTPOK
|
89
|
+
return response
|
90
|
+
when Net::HTTPInternalServerError
|
91
|
+
raise Adyen::REST::ResponseError.new(response.body)
|
92
|
+
when Net::HTTPUnauthorized
|
93
|
+
raise Adyen::REST::Error.new("Webservice credentials are incorrect")
|
94
|
+
else
|
95
|
+
raise Adyen::REST::Error.new("Unexpected HTTP response: #{response.code}")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# The endpoint URI for this client.
|
100
|
+
# @return [URI] The endpoint to use for the environment.
|
101
|
+
def endpoint
|
102
|
+
@endpoint ||= URI(ENDPOINT % [environment])
|
103
|
+
end
|
104
|
+
|
105
|
+
# @see Adyen::REST::Client#endpoint
|
106
|
+
ENDPOINT = 'https://pal-%s.adyen.com/pal/adapter/httppost'
|
107
|
+
private_constant :ENDPOINT
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Adyen
|
2
|
+
module REST
|
3
|
+
|
4
|
+
# The main exception class for error reporting when using the REST API Client.
|
5
|
+
class Error < ::StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Exception class for errors on requests
|
9
|
+
class RequestValidationFailed < Error
|
10
|
+
end
|
11
|
+
|
12
|
+
# Exception class for error responses from the Adyen API.
|
13
|
+
#
|
14
|
+
# @!attribute category
|
15
|
+
# @return [String, nil]
|
16
|
+
# @!attribute code
|
17
|
+
# @return [Integer, nil]
|
18
|
+
# @!attribute description
|
19
|
+
# @return [String, nil]
|
20
|
+
class ResponseError < Error
|
21
|
+
attr_accessor :category, :code, :description
|
22
|
+
|
23
|
+
def initialize(response_body)
|
24
|
+
if match = /\A(\w+)\s(\d+)\s(.*)\z/.match(response_body)
|
25
|
+
@category, @code, @description = match[1], match[2].to_i, match[3]
|
26
|
+
super("API request error: #{description} (code: #{code}/#{category})")
|
27
|
+
else
|
28
|
+
super("API request error: #{response_body}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Adyen
|
2
|
+
module REST
|
3
|
+
|
4
|
+
# This module implements the <b>Payment.capture</b> API to capture
|
5
|
+
# previously authorised payments.
|
6
|
+
module ModifyPayment
|
7
|
+
class Request < Adyen::REST::Request
|
8
|
+
def set_modification_amount(currency, value)
|
9
|
+
self['modification_amount'] = { currency: currency, value: value }
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method :set_amount, :set_modification_amount
|
13
|
+
end
|
14
|
+
|
15
|
+
class Response < Adyen::REST::Response
|
16
|
+
attr_reader :expected_response
|
17
|
+
|
18
|
+
def initialize(http_response, options = {})
|
19
|
+
super
|
20
|
+
@expected_response = options[:expects]
|
21
|
+
end
|
22
|
+
|
23
|
+
def received?
|
24
|
+
self[:response] == expected_response
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Constructs and issues a Payment.capture API call.
|
29
|
+
def capture_payment(attributes = {})
|
30
|
+
request = capture_payment_request(attributes)
|
31
|
+
execute_request(request)
|
32
|
+
end
|
33
|
+
|
34
|
+
def capture_payment_request(attributes = {})
|
35
|
+
Adyen::REST::ModifyPayment::Request.new('Payment.capture', attributes,
|
36
|
+
prefix: 'modification_request',
|
37
|
+
response_class: Adyen::REST::ModifyPayment::Response,
|
38
|
+
response_options: {
|
39
|
+
prefix: 'modification_result',
|
40
|
+
expects: '[capture-received]'
|
41
|
+
}
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Constructs and issues a Payment.cancel API call.
|
46
|
+
def cancel_payment(attributes = {})
|
47
|
+
request = cancel_payment_request(attributes)
|
48
|
+
execute_request(request)
|
49
|
+
end
|
50
|
+
|
51
|
+
def cancel_payment_request(attributes = {})
|
52
|
+
Adyen::REST::ModifyPayment::Request.new('Payment.cancel', attributes,
|
53
|
+
prefix: 'modification_request',
|
54
|
+
response_class: Adyen::REST::ModifyPayment::Response,
|
55
|
+
response_options: {
|
56
|
+
prefix: 'modification_result',
|
57
|
+
expects: '[cancel-received]'
|
58
|
+
}
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Constructs and issues a Payment.cancel API call.
|
63
|
+
def refund_payment(attributes = {})
|
64
|
+
request = refund_payment_request(attributes)
|
65
|
+
execute_request(request)
|
66
|
+
end
|
67
|
+
|
68
|
+
def refund_payment_request(attributes = {})
|
69
|
+
Adyen::REST::ModifyPayment::Request.new('Payment.refund', attributes,
|
70
|
+
prefix: 'modification_request',
|
71
|
+
response_class: Adyen::REST::ModifyPayment::Response,
|
72
|
+
response_options: {
|
73
|
+
prefix: 'modification_result',
|
74
|
+
expects: '[refund-received]'
|
75
|
+
}
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Constructs and issues a Payment.cancel API call.
|
80
|
+
def cancel_or_refund_payment(attributes = {})
|
81
|
+
request = cancel_or_refund_payment_request(attributes)
|
82
|
+
execute_request(request)
|
83
|
+
end
|
84
|
+
|
85
|
+
def cancel_or_refund_payment_request(attributes = {})
|
86
|
+
Adyen::REST::ModifyPayment::Request.new('Payment.cancelOrRefund', attributes,
|
87
|
+
prefix: 'modification_request',
|
88
|
+
response_class: Adyen::REST::ModifyPayment::Response,
|
89
|
+
response_options: {
|
90
|
+
prefix: 'modification_result',
|
91
|
+
expects: '[cancelOrRefund-received]'
|
92
|
+
}
|
93
|
+
)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|