adyen_jpiqueras 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +30 -0
- data/CHANGELOG.md +128 -0
- data/CONTRIBUTING.md +85 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/Rakefile +54 -0
- data/adyen_jpiqueras.gemspec +44 -0
- data/config.ru +5 -0
- data/lib/adyen.rb +16 -0
- data/lib/adyen/api.rb +424 -0
- data/lib/adyen/api/cacert.pem +3894 -0
- data/lib/adyen/api/payment_service.rb +374 -0
- data/lib/adyen/api/recurring_service.rb +188 -0
- data/lib/adyen/api/response.rb +61 -0
- data/lib/adyen/api/simple_soap_client.rb +134 -0
- data/lib/adyen/api/templates/payment_service.rb +159 -0
- data/lib/adyen/api/templates/recurring_service.rb +71 -0
- data/lib/adyen/api/test_helpers.rb +133 -0
- data/lib/adyen/api/xml_querier.rb +137 -0
- data/lib/adyen/base.rb +17 -0
- data/lib/adyen/configuration.rb +179 -0
- data/lib/adyen/form.rb +419 -0
- data/lib/adyen/hpp.rb +27 -0
- data/lib/adyen/hpp/request.rb +192 -0
- data/lib/adyen/hpp/response.rb +52 -0
- data/lib/adyen/hpp/signature.rb +34 -0
- data/lib/adyen/matchers.rb +92 -0
- data/lib/adyen/notification_generator.rb +30 -0
- data/lib/adyen/railtie.rb +13 -0
- data/lib/adyen/rest.rb +67 -0
- data/lib/adyen/rest/authorise_payment.rb +234 -0
- data/lib/adyen/rest/authorise_recurring_payment.rb +46 -0
- data/lib/adyen/rest/client.rb +127 -0
- data/lib/adyen/rest/errors.rb +33 -0
- data/lib/adyen/rest/modify_payment.rb +89 -0
- data/lib/adyen/rest/payout.rb +89 -0
- data/lib/adyen/rest/request.rb +104 -0
- data/lib/adyen/rest/response.rb +80 -0
- data/lib/adyen/rest/signature.rb +27 -0
- data/lib/adyen/signature.rb +76 -0
- data/lib/adyen/templates/notification_migration.rb +29 -0
- data/lib/adyen/templates/notification_model.rb +69 -0
- data/lib/adyen/util.rb +147 -0
- data/lib/adyen/version.rb +5 -0
- data/spec/api/api_spec.rb +231 -0
- data/spec/api/payment_service_spec.rb +505 -0
- data/spec/api/recurring_service_spec.rb +236 -0
- data/spec/api/response_spec.rb +59 -0
- data/spec/api/simple_soap_client_spec.rb +133 -0
- data/spec/api/spec_helper.rb +463 -0
- data/spec/api/test_helpers_spec.rb +84 -0
- data/spec/functional/api_spec.rb +117 -0
- data/spec/functional/initializer.rb.ci +3 -0
- data/spec/functional/initializer.rb.sample +3 -0
- data/spec/spec_helper.rb +8 -0
- data/test/form_test.rb +303 -0
- data/test/functional/payment_authorisation_api_test.rb +107 -0
- data/test/functional/payment_modification_api_test.rb +58 -0
- data/test/functional/payout_api_test.rb +93 -0
- data/test/helpers/capybara.rb +12 -0
- data/test/helpers/configure_adyen.rb +6 -0
- data/test/helpers/example_server.rb +136 -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 +20 -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/hpp/signature_test.rb +37 -0
- data/test/hpp_test.rb +250 -0
- data/test/integration/hpp_integration_test.rb +52 -0
- data/test/integration/payment_using_3d_secure_integration_test.rb +41 -0
- data/test/integration/payment_with_client_side_encryption_integration_test.rb +26 -0
- data/test/rest/signature_test.rb +36 -0
- data/test/rest_list_recurring_details_response_test.rb +22 -0
- data/test/rest_request_test.rb +43 -0
- data/test/rest_response_test.rb +19 -0
- data/test/signature_test.rb +76 -0
- data/test/test_helper.rb +45 -0
- data/test/util_test.rb +78 -0
- data/yard_extensions.rb +16 -0
- metadata +308 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
module Adyen
|
2
|
+
module API
|
3
|
+
# The base class of all responses returned by API calls to Adyen.
|
4
|
+
class Response
|
5
|
+
# Defines shortcut accessor methods, to {Response#params}, for the given parameters.
|
6
|
+
def self.response_attrs(*attrs)
|
7
|
+
attrs.each do |attr|
|
8
|
+
define_method(attr) { params[attr] }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Net::HTTPResponse] The response object returned by Net::HTTP.
|
13
|
+
attr_reader :http_response
|
14
|
+
|
15
|
+
# @param [Net::HTTPResponse] http_response The response object returned by Net::HTTP.
|
16
|
+
def initialize(http_response)
|
17
|
+
@http_response = http_response
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [String] The raw body of the response object.
|
21
|
+
def body
|
22
|
+
@http_response.body
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Boolean] Whether or not the request was successful.
|
26
|
+
def success?
|
27
|
+
!http_failure?
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Boolean] Whether or not the HTTP request was a success.
|
31
|
+
def http_failure?
|
32
|
+
!@http_response.is_a?(Net::HTTPSuccess)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Boolean] Whether or not the SOAP request itself was a success.
|
36
|
+
# Adyen returns a 500 status code for e.g. failed CC validation and in this case, we don't
|
37
|
+
# want to throw a server error but rather treat it as something normal.
|
38
|
+
def server_error?
|
39
|
+
@http_response.is_a?(Net::HTTPServerError) && fault_message.nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [XMLQuerier] The response body wrapped in a XMLQuerier.
|
43
|
+
def xml_querier
|
44
|
+
@xml_querier ||= XMLQuerier.xml(@http_response.body)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Hash] Subclasses return the parsed response body.
|
48
|
+
def params
|
49
|
+
raise "The Adyen::API::Response#params method should be overridden in a subclass."
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [String,nil] The SOAP failure message, if there is one.
|
53
|
+
def fault_message
|
54
|
+
@fault_message ||= begin
|
55
|
+
message = xml_querier.text('//soap:Fault/faultstring')
|
56
|
+
message unless message.empty?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
|
3
|
+
require 'adyen/api/response'
|
4
|
+
require 'adyen/api/xml_querier'
|
5
|
+
|
6
|
+
module Adyen
|
7
|
+
module API
|
8
|
+
# The base class of the API classes that map to Adyen SOAP services.
|
9
|
+
class SimpleSOAPClient
|
10
|
+
# @private
|
11
|
+
ENVELOPE = <<-EOXML.strip.freeze
|
12
|
+
<?xml version="1.0"?>
|
13
|
+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
14
|
+
<soap:Body>
|
15
|
+
%s
|
16
|
+
</soap:Body>
|
17
|
+
</soap:Envelope>
|
18
|
+
EOXML
|
19
|
+
|
20
|
+
# A CA file used to verify certificates when connecting to Adyen.
|
21
|
+
#
|
22
|
+
# @see http://curl.haxx.se/ca/cacert.pem
|
23
|
+
CACERT = File.expand_path('../cacert.pem', __FILE__)
|
24
|
+
|
25
|
+
class StandardError < ::StandardError
|
26
|
+
def initialize(response, action, endpoint)
|
27
|
+
@response, @action, @endpoint = response, action, endpoint
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def message_prefix
|
33
|
+
%{[#{@response.http_response.code} #{@response.http_response.message}] A %s error occurred while calling SOAP action `#{@action}' on endpoint `#{@endpoint}'.}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class ClientError < StandardError
|
38
|
+
def message
|
39
|
+
"#{message_prefix % "client"} Fault message: #{@response.fault_message}."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class ServerError < StandardError
|
44
|
+
def message
|
45
|
+
message_prefix % 'server'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class << self
|
50
|
+
# When a response instance has been assigned, the subsequent call to
|
51
|
+
# {SimpleSOAPClient#call_webservice_action} will not make a remote call, but simply return
|
52
|
+
# the stubbed response instance. This is obviously meant for making payments from tests.
|
53
|
+
#
|
54
|
+
# @see PaymentService::TestHelpers
|
55
|
+
# @see RecurringService::TestHelpers
|
56
|
+
#
|
57
|
+
# @return [Response] The stubbed Response subclass instance.
|
58
|
+
attr_accessor :stubbed_response
|
59
|
+
|
60
|
+
# @return [URI] A URI based on the ENDPOINT_URI constant defined on subclasses, where
|
61
|
+
# the environment type has been interpolated. E.g. Test environment.
|
62
|
+
def endpoint
|
63
|
+
@endpoint ||= URI.parse(const_get('ENDPOINT_URI') % Adyen.configuration.environment)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Hash] A hash of key-value pairs required for the action that is to be called.
|
68
|
+
attr_reader :params
|
69
|
+
|
70
|
+
# @param [Hash] params A hash of key-value pairs required for the action that is to be called.
|
71
|
+
# These are merged with the Adyen::API.default_params.
|
72
|
+
def initialize(params = {})
|
73
|
+
@params = Adyen.configuration.default_api_params.merge(params)
|
74
|
+
end
|
75
|
+
|
76
|
+
def validate_parameter_value!(param, value)
|
77
|
+
if value.nil? || value =~ /^\s*$/
|
78
|
+
raise ArgumentError, "The required parameter `:#{param}' is missing."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def validate_parameters!(*params)
|
83
|
+
params.each do |param|
|
84
|
+
case param
|
85
|
+
when Symbol
|
86
|
+
validate_parameter_value!(param, @params[param])
|
87
|
+
when Hash
|
88
|
+
param.each do |name, attrs|
|
89
|
+
validate_parameter_value!(name, @params[name])
|
90
|
+
attrs.each { |attr| validate_parameter_value!("#{name} => :#{attr}", @params[name][attr]) }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# This method wraps the given XML +data+ in a SOAP envelope and posts it to +action+ on the
|
97
|
+
# +endpoint+ defined for the subclass.
|
98
|
+
#
|
99
|
+
# The result is a response object, with XMLQuerier, ready to be queried.
|
100
|
+
#
|
101
|
+
# If a {stubbed_response} has been set, then said response is returned and no actual remote
|
102
|
+
# calls are made.
|
103
|
+
#
|
104
|
+
# @param [String] action The remote action to call.
|
105
|
+
# @param [String] data The XML data to post to the remote action.
|
106
|
+
# @param [Response] response_class The Response subclass used to wrap the response from Adyen.
|
107
|
+
def call_webservice_action(action, data, response_class)
|
108
|
+
if response = self.class.stubbed_response
|
109
|
+
self.class.stubbed_response = nil
|
110
|
+
response
|
111
|
+
else
|
112
|
+
endpoint = self.class.endpoint
|
113
|
+
|
114
|
+
post = Net::HTTP::Post.new(endpoint.path, 'Accept' => 'text/xml', 'Content-Type' => 'text/xml; charset=utf-8', 'SOAPAction' => action)
|
115
|
+
post.basic_auth(Adyen.configuration.api_username, Adyen.configuration.api_password)
|
116
|
+
post.body = ENVELOPE % data
|
117
|
+
|
118
|
+
request = Net::HTTP.new(endpoint.host, endpoint.port)
|
119
|
+
request.use_ssl = true
|
120
|
+
request.ca_file = CACERT
|
121
|
+
request.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
122
|
+
|
123
|
+
request.start do |http|
|
124
|
+
http_response = http.request(post)
|
125
|
+
response = response_class.new(http_response)
|
126
|
+
raise ClientError.new(response, action, endpoint) if http_response.is_a?(Net::HTTPClientError)
|
127
|
+
raise ServerError.new(response, action, endpoint) if response.server_error?
|
128
|
+
response
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module Adyen
|
2
|
+
module API
|
3
|
+
class PaymentService < SimpleSOAPClient
|
4
|
+
class << self
|
5
|
+
private
|
6
|
+
|
7
|
+
def modification_request(method, body = nil)
|
8
|
+
<<-EOXML
|
9
|
+
<payment:#{method} xmlns:payment="http://payment.services.adyen.com" xmlns:recurring="http://recurring.services.adyen.com" xmlns:common="http://common.services.adyen.com">
|
10
|
+
<payment:modificationRequest>
|
11
|
+
<payment:merchantAccount>%s</payment:merchantAccount>
|
12
|
+
<payment:originalReference>%s</payment:originalReference>
|
13
|
+
#{body}
|
14
|
+
</payment:modificationRequest>
|
15
|
+
</payment:#{method}>
|
16
|
+
EOXML
|
17
|
+
end
|
18
|
+
|
19
|
+
def modification_request_with_amount(method)
|
20
|
+
modification_request(method, <<-EOXML)
|
21
|
+
<payment:modificationAmount>
|
22
|
+
<common:currency>%s</common:currency>
|
23
|
+
<common:value>%s</common:value>
|
24
|
+
</payment:modificationAmount>
|
25
|
+
EOXML
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @private
|
30
|
+
CAPTURE_LAYOUT = modification_request_with_amount(:capture)
|
31
|
+
# @private
|
32
|
+
REFUND_LAYOUT = modification_request_with_amount(:refund)
|
33
|
+
# @private
|
34
|
+
CANCEL_LAYOUT = modification_request(:cancel)
|
35
|
+
# @private
|
36
|
+
CANCEL_OR_REFUND_LAYOUT = modification_request(:cancelOrRefund)
|
37
|
+
|
38
|
+
# @private
|
39
|
+
LAYOUT = <<-EOXML
|
40
|
+
<payment:authorise xmlns:payment="http://payment.services.adyen.com" xmlns:recurring="http://recurring.services.adyen.com" xmlns:common="http://common.services.adyen.com">
|
41
|
+
<payment:paymentRequest>
|
42
|
+
<payment:merchantAccount>%s</payment:merchantAccount>
|
43
|
+
<payment:reference>%s</payment:reference>
|
44
|
+
%s
|
45
|
+
</payment:paymentRequest>
|
46
|
+
</payment:authorise>
|
47
|
+
EOXML
|
48
|
+
|
49
|
+
# @private
|
50
|
+
AMOUNT_PARTIAL = <<-EOXML
|
51
|
+
<payment:amount>
|
52
|
+
<common:currency>%s</common:currency>
|
53
|
+
<common:value>%s</common:value>
|
54
|
+
</payment:amount>
|
55
|
+
EOXML
|
56
|
+
|
57
|
+
# @private
|
58
|
+
CARD_PARTIAL = <<-EOXML
|
59
|
+
<payment:card>
|
60
|
+
<payment:holderName>%s</payment:holderName>
|
61
|
+
<payment:number>%s</payment:number>
|
62
|
+
<payment:expiryYear>%s</payment:expiryYear>
|
63
|
+
<payment:expiryMonth>%02d</payment:expiryMonth>
|
64
|
+
%s
|
65
|
+
</payment:card>
|
66
|
+
EOXML
|
67
|
+
|
68
|
+
# @private
|
69
|
+
CARD_CVC_PARTIAL = <<-EOXML
|
70
|
+
<payment:cvc>%s</payment:cvc>
|
71
|
+
EOXML
|
72
|
+
|
73
|
+
# @private
|
74
|
+
ONE_CLICK_CARD_PARTIAL = <<-EOXML
|
75
|
+
<payment:card>
|
76
|
+
<payment:cvc>%s</payment:cvc>
|
77
|
+
</payment:card>
|
78
|
+
EOXML
|
79
|
+
|
80
|
+
# @private
|
81
|
+
INSTALLMENTS_PARTIAL = <<-EOXML
|
82
|
+
<payment:installments>
|
83
|
+
<common:value>%s</common:value>
|
84
|
+
</payment:installments>
|
85
|
+
EOXML
|
86
|
+
|
87
|
+
SOCIAL_SECURITY_NUMBER_PARTIAL = <<-EOXML
|
88
|
+
<payment:socialSecurityNumber>%s</payment:socialSecurityNumber>
|
89
|
+
EOXML
|
90
|
+
|
91
|
+
# @private
|
92
|
+
DELIVERY_DATE_PARTIAL = <<-EOXML
|
93
|
+
<deliveryDate xmlns="http://payment.services.adyen.com">%s</deliveryDate>
|
94
|
+
EOXML
|
95
|
+
|
96
|
+
# @private
|
97
|
+
SELECTED_BRAND_PARTIAL = <<-EOXML
|
98
|
+
<payment:selectedBrand>%s</payment:selectedBrand>
|
99
|
+
EOXML
|
100
|
+
|
101
|
+
# @private
|
102
|
+
SHOPPER_NAME_PARTIAL = <<-EOXML
|
103
|
+
<payment:shopperName>
|
104
|
+
<common:firstName>%s</common:firstName>
|
105
|
+
<common:lastName>%s</common:lastName>
|
106
|
+
</payment:shopperName>
|
107
|
+
EOXML
|
108
|
+
|
109
|
+
# @private
|
110
|
+
ENCRYPTED_CARD_PARTIAL = <<-EOXML
|
111
|
+
<additionalAmount xmlns="http://payment.services.adyen.com" xsi:nil="true" />
|
112
|
+
<additionalData xmlns="http://payment.services.adyen.com">
|
113
|
+
<entry>
|
114
|
+
<key xsi:type="xsd:string">card.encrypted.json</key>
|
115
|
+
<value xsi:type="xsd:string">%s</value>
|
116
|
+
</entry>
|
117
|
+
</additionalData>
|
118
|
+
EOXML
|
119
|
+
|
120
|
+
# @private
|
121
|
+
ENABLE_RECURRING_CONTRACTS_PARTIAL = <<-EOXML
|
122
|
+
<payment:recurring>
|
123
|
+
<payment:contract>RECURRING,ONECLICK</payment:contract>
|
124
|
+
</payment:recurring>
|
125
|
+
EOXML
|
126
|
+
|
127
|
+
# @private
|
128
|
+
RECURRING_PAYMENT_BODY_PARTIAL = <<-EOXML
|
129
|
+
<payment:recurring>
|
130
|
+
<payment:contract>RECURRING</payment:contract>
|
131
|
+
</payment:recurring>
|
132
|
+
<payment:selectedRecurringDetailReference>%s</payment:selectedRecurringDetailReference>
|
133
|
+
<payment:shopperInteraction>ContAuth</payment:shopperInteraction>
|
134
|
+
EOXML
|
135
|
+
|
136
|
+
# @private
|
137
|
+
ONE_CLICK_PAYMENT_BODY_PARTIAL = <<-EOXML
|
138
|
+
<payment:recurring>
|
139
|
+
<payment:contract>ONECLICK</payment:contract>
|
140
|
+
</payment:recurring>
|
141
|
+
<payment:selectedRecurringDetailReference>%s</payment:selectedRecurringDetailReference>
|
142
|
+
EOXML
|
143
|
+
|
144
|
+
# @private
|
145
|
+
SHOPPER_PARTIALS = {
|
146
|
+
:reference => ' <payment:shopperReference>%s</payment:shopperReference>',
|
147
|
+
:email => ' <payment:shopperEmail>%s</payment:shopperEmail>',
|
148
|
+
:ip => ' <payment:shopperIP>%s</payment:shopperIP>',
|
149
|
+
:statement => ' <payment:shopperStatement>%s</payment:shopperStatement>',
|
150
|
+
}
|
151
|
+
|
152
|
+
# @private
|
153
|
+
FRAUD_OFFSET_PARTIAL = '<payment:fraudOffset>%s</payment:fraudOffset>'
|
154
|
+
|
155
|
+
# @private
|
156
|
+
CAPTURE_DELAY_PARTIAL = '<payment:captureDelayHours>%s</payment:captureDelayHours>'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Adyen
|
2
|
+
module API
|
3
|
+
class RecurringService < SimpleSOAPClient
|
4
|
+
# @private
|
5
|
+
LIST_LAYOUT = <<EOS
|
6
|
+
<recurring:listRecurringDetails xmlns:payment="http://payment.services.adyen.com" xmlns:recurring="http://recurring.services.adyen.com">
|
7
|
+
<recurring:request>
|
8
|
+
<recurring:recurring>
|
9
|
+
<payment:contract>RECURRING</payment:contract>
|
10
|
+
</recurring:recurring>
|
11
|
+
<recurring:merchantAccount>%s</recurring:merchantAccount>
|
12
|
+
<recurring:shopperReference>%s</recurring:shopperReference>
|
13
|
+
</recurring:request>
|
14
|
+
</recurring:listRecurringDetails>
|
15
|
+
EOS
|
16
|
+
|
17
|
+
# @private
|
18
|
+
DISABLE_LAYOUT = <<EOS
|
19
|
+
<recurring:disable xmlns:recurring="http://recurring.services.adyen.com">
|
20
|
+
<recurring:request>
|
21
|
+
<recurring:merchantAccount>%s</recurring:merchantAccount>
|
22
|
+
<recurring:shopperReference>%s</recurring:shopperReference>
|
23
|
+
%s
|
24
|
+
</recurring:request>
|
25
|
+
</recurring:disable>
|
26
|
+
EOS
|
27
|
+
|
28
|
+
# @private
|
29
|
+
RECURRING_DETAIL_PARTIAL = <<EOS
|
30
|
+
<recurring:recurringDetailReference>%s</recurring:recurringDetailReference>
|
31
|
+
EOS
|
32
|
+
|
33
|
+
STORE_TOKEN_LAYOUT = <<EOS
|
34
|
+
<recurring:storeToken xmlns:recurring="http://recurring.services.adyen.com" xmlns:payment="http://payment.services.adyen.com">
|
35
|
+
<recurring:request>
|
36
|
+
<recurring:recurring>
|
37
|
+
<payment:contract>RECURRING</payment:contract>
|
38
|
+
</recurring:recurring>
|
39
|
+
<recurring:merchantAccount>%s</recurring:merchantAccount>
|
40
|
+
<recurring:shopperReference>%s</recurring:shopperReference>
|
41
|
+
<recurring:shopperEmail>%s</recurring:shopperEmail>
|
42
|
+
%s
|
43
|
+
</recurring:request>
|
44
|
+
</recurring:storeToken>
|
45
|
+
EOS
|
46
|
+
|
47
|
+
# @private
|
48
|
+
CARD_PARTIAL = <<EOS
|
49
|
+
<recurring:card>
|
50
|
+
<payment:holderName>%s</payment:holderName>
|
51
|
+
<payment:number>%s</payment:number>
|
52
|
+
<payment:cvc>%s</payment:cvc>
|
53
|
+
<payment:expiryYear>%s</payment:expiryYear>
|
54
|
+
<payment:expiryMonth>%02d</payment:expiryMonth>
|
55
|
+
</recurring:card>
|
56
|
+
EOS
|
57
|
+
# Electronic bank debit in Germany. Semi real-time payment method.
|
58
|
+
# @private
|
59
|
+
ELV_PARTIAL = <<EOS
|
60
|
+
<recurring:elv>
|
61
|
+
<payment:bankLocation>%s</payment:bankLocation>
|
62
|
+
<payment:bankName>%s</payment:bankName>
|
63
|
+
<payment:bankLocationId>%s</payment:bankLocationId>
|
64
|
+
<payment:accountHolderName>%s</payment:accountHolderName>
|
65
|
+
<payment:bankAccountNumber>%02d</payment:bankAccountNumber>
|
66
|
+
</recurring:elv>
|
67
|
+
EOS
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'adyen/api/payment_service'
|
2
|
+
|
3
|
+
module Adyen
|
4
|
+
module API
|
5
|
+
class PaymentService < SimpleSOAPClient
|
6
|
+
# A collection of test helpers that create and assign stubbed response instances for a
|
7
|
+
# subsequent remote call.
|
8
|
+
#
|
9
|
+
# This module extends the {PaymentService} class and thus these methods are callable on it.
|
10
|
+
module TestHelpers
|
11
|
+
AUTHORISE_RESPONSE = SimpleSOAPClient::ENVELOPE % <<-EOXML
|
12
|
+
<ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
|
13
|
+
<ns1:paymentResult>
|
14
|
+
<additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
15
|
+
<authCode xmlns="http://payment.services.adyen.com">1234</authCode>
|
16
|
+
<dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
17
|
+
<dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
18
|
+
<fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
19
|
+
<issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
20
|
+
<md xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
21
|
+
<paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
22
|
+
<pspReference xmlns="http://payment.services.adyen.com">9876543210987654</pspReference>
|
23
|
+
<refusalReason xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
24
|
+
<resultCode xmlns="http://payment.services.adyen.com">Authorised</resultCode>
|
25
|
+
</ns1:paymentResult>
|
26
|
+
</ns1:authoriseResponse>
|
27
|
+
EOXML
|
28
|
+
|
29
|
+
AUTHORISATION_REFUSED_RESPONSE = SimpleSOAPClient::ENVELOPE % <<-EOXML
|
30
|
+
<ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
|
31
|
+
<ns1:paymentResult>
|
32
|
+
<additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
33
|
+
<authCode xmlns="http://payment.services.adyen.com">1234</authCode>
|
34
|
+
<dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
35
|
+
<dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
36
|
+
<fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
37
|
+
<issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
38
|
+
<md xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
39
|
+
<paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
|
40
|
+
<pspReference xmlns="http://payment.services.adyen.com">9876543210987654</pspReference>
|
41
|
+
<refusalReason xmlns="http://payment.services.adyen.com">You need to actually own money.</refusalReason>
|
42
|
+
<resultCode xmlns="http://payment.services.adyen.com">Refused</resultCode>
|
43
|
+
</ns1:paymentResult>
|
44
|
+
</ns1:authoriseResponse>
|
45
|
+
EOXML
|
46
|
+
|
47
|
+
AUTHORISATION_REQUEST_INVALID_RESPONSE = SimpleSOAPClient::ENVELOPE % <<-EOXML
|
48
|
+
<soap:Fault>
|
49
|
+
<faultcode>soap:Server</faultcode>
|
50
|
+
<faultstring>validation 101 Invalid card number</faultstring>
|
51
|
+
</soap:Fault>
|
52
|
+
EOXML
|
53
|
+
|
54
|
+
# @return [AuthorisationResponse] A authorisation succeeded response instance.
|
55
|
+
def success_stub
|
56
|
+
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
57
|
+
def http_response.body; AUTHORISE_RESPONSE; end
|
58
|
+
PaymentService::AuthorisationResponse.new(http_response)
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [AuthorisationResponse] An authorisation refused response instance.
|
62
|
+
def refused_stub
|
63
|
+
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
64
|
+
def http_response.body; AUTHORISATION_REFUSED_RESPONSE; end
|
65
|
+
PaymentService::AuthorisationResponse.new(http_response)
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [AuthorisationResponse] An ‘invalid request’ response instance.
|
69
|
+
def invalid_stub
|
70
|
+
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
71
|
+
def http_response.body; AUTHORISATION_REQUEST_INVALID_RESPONSE; end
|
72
|
+
PaymentService::AuthorisationResponse.new(http_response)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Assigns a {#success_stub}, meaning the subsequent authoristaion request will be authorised.
|
76
|
+
#
|
77
|
+
# @return [AuthorisationResponse] A authorisation succeeded response instance.
|
78
|
+
def stub_success!
|
79
|
+
@stubbed_response = success_stub
|
80
|
+
end
|
81
|
+
|
82
|
+
# Assigns a {#refused_stub}, meaning the subsequent authoristaion request will be refused.
|
83
|
+
#
|
84
|
+
# @return [AuthorisationResponse] An authorisation refused response instance.
|
85
|
+
def stub_refused!
|
86
|
+
@stubbed_response = refused_stub
|
87
|
+
end
|
88
|
+
|
89
|
+
# Assigns a {#invalid_stub}, meaning the subsequent authoristaion request will be refused,
|
90
|
+
# because the request was invalid.
|
91
|
+
#
|
92
|
+
# @return [AuthorisationResponse] An ‘invalid request’ response instance.
|
93
|
+
def stub_invalid!
|
94
|
+
@stubbed_response = invalid_stub
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
extend TestHelpers
|
99
|
+
end
|
100
|
+
|
101
|
+
class RecurringService < SimpleSOAPClient
|
102
|
+
# A collection of test helpers that create and assign stubbed response instances for a
|
103
|
+
# subsequent remote call.
|
104
|
+
#
|
105
|
+
# This module extends the {RecurringService} class and thus these methods are callable on it.
|
106
|
+
module TestHelpers
|
107
|
+
DISABLE_RESPONSE = SimpleSOAPClient::ENVELOPE % <<-EOXML
|
108
|
+
<ns1:disableResponse xmlns:ns1="http://recurring.services.adyen.com">
|
109
|
+
<ns1:result>
|
110
|
+
<response xmlns="http://recurring.services.adyen.com">
|
111
|
+
%s
|
112
|
+
</response>
|
113
|
+
</ns1:result>
|
114
|
+
</ns1:disableResponse>
|
115
|
+
EOXML
|
116
|
+
|
117
|
+
# @return [DisableResponse] A ‘disable succeeded’ response instance.
|
118
|
+
def disabled_stub
|
119
|
+
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
120
|
+
def http_response.body; DISABLE_RESPONSE % DisableResponse::DISABLED_RESPONSES.first; end
|
121
|
+
RecurringService::DisableResponse.new(http_response)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Assigns a {#disabled_stub}, meaning the subsequent disable request will be successful.
|
125
|
+
def stub_disabled!
|
126
|
+
@stubbed_response = disabled_stub
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
extend TestHelpers
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|