adyen_jpiqueras 2.3.0

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