adyen_jpiqueras 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.travis.yml +30 -0
  4. data/CHANGELOG.md +128 -0
  5. data/CONTRIBUTING.md +85 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +21 -0
  8. data/README.md +31 -0
  9. data/Rakefile +54 -0
  10. data/adyen_jpiqueras.gemspec +44 -0
  11. data/config.ru +5 -0
  12. data/lib/adyen.rb +16 -0
  13. data/lib/adyen/api.rb +424 -0
  14. data/lib/adyen/api/cacert.pem +3894 -0
  15. data/lib/adyen/api/payment_service.rb +374 -0
  16. data/lib/adyen/api/recurring_service.rb +188 -0
  17. data/lib/adyen/api/response.rb +61 -0
  18. data/lib/adyen/api/simple_soap_client.rb +134 -0
  19. data/lib/adyen/api/templates/payment_service.rb +159 -0
  20. data/lib/adyen/api/templates/recurring_service.rb +71 -0
  21. data/lib/adyen/api/test_helpers.rb +133 -0
  22. data/lib/adyen/api/xml_querier.rb +137 -0
  23. data/lib/adyen/base.rb +17 -0
  24. data/lib/adyen/configuration.rb +179 -0
  25. data/lib/adyen/form.rb +419 -0
  26. data/lib/adyen/hpp.rb +27 -0
  27. data/lib/adyen/hpp/request.rb +192 -0
  28. data/lib/adyen/hpp/response.rb +52 -0
  29. data/lib/adyen/hpp/signature.rb +34 -0
  30. data/lib/adyen/matchers.rb +92 -0
  31. data/lib/adyen/notification_generator.rb +30 -0
  32. data/lib/adyen/railtie.rb +13 -0
  33. data/lib/adyen/rest.rb +67 -0
  34. data/lib/adyen/rest/authorise_payment.rb +234 -0
  35. data/lib/adyen/rest/authorise_recurring_payment.rb +46 -0
  36. data/lib/adyen/rest/client.rb +127 -0
  37. data/lib/adyen/rest/errors.rb +33 -0
  38. data/lib/adyen/rest/modify_payment.rb +89 -0
  39. data/lib/adyen/rest/payout.rb +89 -0
  40. data/lib/adyen/rest/request.rb +104 -0
  41. data/lib/adyen/rest/response.rb +80 -0
  42. data/lib/adyen/rest/signature.rb +27 -0
  43. data/lib/adyen/signature.rb +76 -0
  44. data/lib/adyen/templates/notification_migration.rb +29 -0
  45. data/lib/adyen/templates/notification_model.rb +69 -0
  46. data/lib/adyen/util.rb +147 -0
  47. data/lib/adyen/version.rb +5 -0
  48. data/spec/api/api_spec.rb +231 -0
  49. data/spec/api/payment_service_spec.rb +505 -0
  50. data/spec/api/recurring_service_spec.rb +236 -0
  51. data/spec/api/response_spec.rb +59 -0
  52. data/spec/api/simple_soap_client_spec.rb +133 -0
  53. data/spec/api/spec_helper.rb +463 -0
  54. data/spec/api/test_helpers_spec.rb +84 -0
  55. data/spec/functional/api_spec.rb +117 -0
  56. data/spec/functional/initializer.rb.ci +3 -0
  57. data/spec/functional/initializer.rb.sample +3 -0
  58. data/spec/spec_helper.rb +8 -0
  59. data/test/form_test.rb +303 -0
  60. data/test/functional/payment_authorisation_api_test.rb +107 -0
  61. data/test/functional/payment_modification_api_test.rb +58 -0
  62. data/test/functional/payout_api_test.rb +93 -0
  63. data/test/helpers/capybara.rb +12 -0
  64. data/test/helpers/configure_adyen.rb +6 -0
  65. data/test/helpers/example_server.rb +136 -0
  66. data/test/helpers/public/adyen.encrypt.js +679 -0
  67. data/test/helpers/public/adyen.encrypt.min.js +14 -0
  68. data/test/helpers/test_cards.rb +20 -0
  69. data/test/helpers/views/authorized.erb +7 -0
  70. data/test/helpers/views/hpp.erb +20 -0
  71. data/test/helpers/views/index.erb +6 -0
  72. data/test/helpers/views/pay.erb +36 -0
  73. data/test/helpers/views/redirect_shopper.erb +18 -0
  74. data/test/hpp/signature_test.rb +37 -0
  75. data/test/hpp_test.rb +250 -0
  76. data/test/integration/hpp_integration_test.rb +52 -0
  77. data/test/integration/payment_using_3d_secure_integration_test.rb +41 -0
  78. data/test/integration/payment_with_client_side_encryption_integration_test.rb +26 -0
  79. data/test/rest/signature_test.rb +36 -0
  80. data/test/rest_list_recurring_details_response_test.rb +22 -0
  81. data/test/rest_request_test.rb +43 -0
  82. data/test/rest_response_test.rb +19 -0
  83. data/test/signature_test.rb +76 -0
  84. data/test/test_helper.rb +45 -0
  85. data/test/util_test.rb +78 -0
  86. data/yard_extensions.rb +16 -0
  87. 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