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,236 @@
1
+ # encoding: UTF-8
2
+ require 'api/spec_helper'
3
+ require 'date'
4
+
5
+ describe Adyen::API::RecurringService do
6
+ include APISpecHelper
7
+
8
+ before do
9
+ @params = {
10
+ :reference => 'order-id',
11
+ :amount => {
12
+ :currency => 'EUR',
13
+ :value => '1234',
14
+ },
15
+ :shopper => {
16
+ :email => 's.hopper@example.com',
17
+ :reference => 'user-id',
18
+ :ip => '61.294.12.12',
19
+ :statement => 'invoice number 123456'
20
+ },
21
+ :card => {
22
+ :expiry_month => 12,
23
+ :expiry_year => 2012,
24
+ :holder_name => 'Simon わくわく Hopper',
25
+ :number => '4444333322221111',
26
+ :cvc => '737',
27
+ # Maestro UK/Solo only
28
+ #:issue_number => ,
29
+ #:start_month => ,
30
+ #:start_year => ,
31
+ },
32
+ # German's Direct Debit (Elektronisches Lastschriftverfahren)
33
+ :elv => {
34
+ :holder_name => 'Simon わくわく Hopper',
35
+ :number => '1234567890',
36
+ :bank_location => 'Berlin',
37
+ :bank_location_id => '12345678',
38
+ :bank_name => 'TestBank',
39
+ }
40
+ }
41
+ @recurring = @object = Adyen::API::RecurringService.new(@params)
42
+ end
43
+
44
+ describe_request_body_of :list, '//recurring:listRecurringDetails/recurring:request' do
45
+ it_should_validate_request_parameters :merchant_account,
46
+ :shopper => [:reference]
47
+
48
+ it "includes the merchant account handle" do
49
+ text('./recurring:merchantAccount').should == 'SuperShopper'
50
+ end
51
+
52
+ it "includes the shopper’s reference" do
53
+ text('./recurring:shopperReference').should == 'user-id'
54
+ end
55
+
56
+ it "includes the type of contract, which is always `RECURRING'" do
57
+ text('./recurring:recurring/payment:contract').should == 'RECURRING'
58
+ end
59
+ end
60
+
61
+ describe_response_from :list, LIST_RESPONSE, 'listRecurringDetails' do
62
+ it_should_return_params_for_each_xml_backend({
63
+ :creation_date => DateTime.parse('2009-10-27T11:26:22.203+01:00'),
64
+ :last_known_shopper_email => 's.hopper@example.com',
65
+ :shopper_reference => 'user-id',
66
+ :details => [
67
+ {
68
+ :card => {
69
+ :expiry_date => Date.new(2012, 12, 31),
70
+ :holder_name => 'S. Hopper',
71
+ :number => '1111'
72
+ },
73
+ :recurring_detail_reference => 'RecurringDetailReference1',
74
+ :variant => 'mc',
75
+ :creation_date => DateTime.parse('2009-10-27T11:50:12.178+01:00')
76
+ },
77
+ {
78
+ :bank => {
79
+ :number => '123456789',
80
+ :bank_location_id => 'bank-location-id',
81
+ :bank_name => 'AnyBank',
82
+ :bic => 'BBBBCCLLbbb',
83
+ :country_code => 'NL',
84
+ :iban => 'NL69PSTB0001234567',
85
+ :holder_name => 'S. Hopper'
86
+ },
87
+ :recurring_detail_reference => 'RecurringDetailReference2',
88
+ :variant => 'IDEAL',
89
+ :creation_date => DateTime.parse('2009-10-27T11:26:22.216+01:00')
90
+ },
91
+ {
92
+ :elv => {
93
+ :holder_name => 'S. Hopper',
94
+ :number => '1234567890',
95
+ :bank_location => 'Berlin',
96
+ :bank_location_id => '12345678',
97
+ :bank_name => 'TestBank',
98
+ },
99
+ :recurring_detail_reference => 'RecurringDetailReference3',
100
+ :variant => 'elv',
101
+ :creation_date => DateTime.parse('2009-10-27T11:26:22.216+01:00')
102
+ }
103
+ ],
104
+ })
105
+
106
+ it "returns an array with just the detail references" do
107
+ @response.references.should == %w{ RecurringDetailReference1 RecurringDetailReference2 RecurringDetailReference3 }
108
+ end
109
+ end
110
+
111
+ describe_response_from :list, LIST_EMPTY_RESPONSE, 'listRecurringDetails' do
112
+ it "returns an empty hash when there are no details" do
113
+ @recurring.list.params.should == {}
114
+ end
115
+
116
+ it "returns an empty array when there are no references" do
117
+ @response.references.should == []
118
+ end
119
+ end
120
+
121
+ describe_request_body_of :disable, '//recurring:disable/recurring:request' do
122
+ it_should_validate_request_parameters :merchant_account,
123
+ :shopper => [:reference]
124
+
125
+ it "includes the merchant account handle" do
126
+ text('./recurring:merchantAccount').should == 'SuperShopper'
127
+ end
128
+
129
+ it "includes the shopper’s reference" do
130
+ text('./recurring:shopperReference').should == 'user-id'
131
+ end
132
+
133
+ it "includes the shopper’s recurring detail reference if it is given" do
134
+ xpath('./recurring:recurringDetailReference').should be_empty
135
+ @recurring.params[:recurring_detail_reference] = 'RecurringDetailReference1'
136
+ text('./recurring:recurringDetailReference').should == 'RecurringDetailReference1'
137
+ end
138
+ end
139
+
140
+ describe_response_from :disable, (DISABLE_RESPONSE % '[detail-successfully-disabled]'), 'disable' do
141
+ it "returns whether or not it was disabled" do
142
+ @response.should be_success
143
+ @response.should be_disabled
144
+
145
+ stub_net_http(DISABLE_RESPONSE % '[all-details-successfully-disabled]')
146
+ @response = @recurring.disable
147
+ @response.should be_success
148
+ @response.should be_disabled
149
+ end
150
+
151
+ it_should_return_params_for_each_xml_backend(:response => '[detail-successfully-disabled]')
152
+ end
153
+
154
+ describe_request_body_of :store_token, '//recurring:storeToken/recurring:request' do
155
+ it_should_validate_request_parameters :merchant_account,
156
+ :shopper => [:email, :reference]
157
+
158
+ it "includes the merchant account handle" do
159
+ text('./recurring:merchantAccount').should == 'SuperShopper'
160
+ end
161
+
162
+ it "includes the shopper’s reference" do
163
+ text('./recurring:shopperReference').should == 'user-id'
164
+ end
165
+
166
+ it "includes the shopper’s email" do
167
+ text('./recurring:shopperEmail').should == 's.hopper@example.com'
168
+ end
169
+
170
+ it "includes the creditcard details" do
171
+ xpath('./recurring:card') do |card|
172
+ # there's no reason why Nokogiri should escape these characters, but as long as they're correct
173
+ card.text('./payment:holderName').should == 'Simon わくわく Hopper'
174
+ card.text('./payment:number').should == '4444333322221111'
175
+ card.text('./payment:cvc').should == '737'
176
+ card.text('./payment:expiryMonth').should == '12'
177
+ card.text('./payment:expiryYear').should == '2012'
178
+ end
179
+ end
180
+
181
+ it "formats the creditcard’s expiry month as a two digit number" do
182
+ @recurring.params[:card][:expiry_month] = 6
183
+ text('./recurring:card/payment:expiryMonth').should == '06'
184
+ end
185
+
186
+ it "includes the necessary recurring and one-click contract info if the `:recurring' param is truthful" do
187
+ text('./recurring:recurring/payment:contract').should == 'RECURRING'
188
+ end
189
+ end
190
+
191
+ describe_request_body_of :store_token, '//recurring:storeToken/recurring:request' do
192
+ it_should_validate_request_parameters :merchant_account,
193
+ :shopper => [:email, :reference]
194
+
195
+ it "includes the merchant account handle" do
196
+ text('./recurring:merchantAccount').should == 'SuperShopper'
197
+ end
198
+
199
+ it "includes the shopper’s reference" do
200
+ text('./recurring:shopperReference').should == 'user-id'
201
+ end
202
+
203
+ it "includes the shopper’s email" do
204
+ text('./recurring:shopperEmail').should == 's.hopper@example.com'
205
+ end
206
+
207
+ it "includes the ELV details" do
208
+ xpath('./recurring:elv') do |elv|
209
+ # there's no reason why Nokogiri should escape these characters, but as long as they're correct
210
+ elv.text('./payment:accountHolderName').should == 'Simon わくわく Hopper'
211
+ elv.text('./payment:bankAccountNumber').should == '1234567890'
212
+ elv.text('./payment:bankLocation').should == 'Berlin'
213
+ elv.text('./payment:bankLocationId').should == '12345678'
214
+ elv.text('./payment:bankName').should == 'TestBank'
215
+ end
216
+ end
217
+
218
+ it "includes the necessary recurring and one-click contract info if the `:recurring' param is truthful" do
219
+ text('./recurring:recurring/payment:contract').should == 'RECURRING'
220
+ end
221
+ end
222
+
223
+ describe_response_from :disable, (DISABLE_RESPONSE % '[detail-successfully-disabled]'), 'disable' do
224
+ it "returns whether or not it was disabled" do
225
+ @response.should be_success
226
+ @response.should be_disabled
227
+
228
+ stub_net_http(DISABLE_RESPONSE % '[all-details-successfully-disabled]')
229
+ @response = @recurring.disable
230
+ @response.should be_success
231
+ @response.should be_disabled
232
+ end
233
+
234
+ it_should_return_params_for_each_xml_backend(:response => '[detail-successfully-disabled]')
235
+ end
236
+ end
@@ -0,0 +1,59 @@
1
+ # encoding: UTF-8
2
+ require 'api/spec_helper'
3
+
4
+ describe Adyen::API::Response do
5
+ before do
6
+ http_response = Net::HTTPOK.new('1.1', '200', 'OK')
7
+ http_response.add_field('Content-type', 'text/xml')
8
+ http_response.stub(:body).and_return(AUTHORISE_RESPONSE)
9
+ @response = Adyen::API::Response.new(http_response)
10
+ end
11
+
12
+ it "returns a XMLQuerier instance with the response body" do
13
+ @response.xml_querier.should be_instance_of(Adyen::API::XMLQuerier)
14
+ @response.xml_querier.to_s.rstrip.should == AUTHORISE_RESPONSE.rstrip
15
+ end
16
+
17
+ describe "with a successful HTTP response" do
18
+ it "returns that the (HTTP) request was a success" do
19
+ @response.should_not be_a_http_failure
20
+ @response.should be_a_success
21
+ end
22
+ end
23
+
24
+ describe "with a failed HTTP response" do
25
+ before do
26
+ http_response = Net::HTTPBadRequest.new('1.1', '400', 'Bad request')
27
+ @response = Adyen::API::Response.new(http_response)
28
+ end
29
+
30
+ it "returns that the (HTTP) request was not a success" do
31
+ @response.should be_a_http_failure
32
+ @response.should_not be_a_success
33
+ end
34
+ end
35
+
36
+ describe "with a server error HTTP response and _no_ SOAP fault message" do
37
+ before do
38
+ http_response = Net::HTTPServerError.new('1.1', '500', 'Internal Server Error')
39
+ http_response.stub(:body).and_return(%{<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"><soap:Body></soap:Body></soap:Envelope>})
40
+ @response = Adyen::API::Response.new(http_response)
41
+ end
42
+
43
+ it "`server_error?` returns that the (HTTP) request did cause a server error" do
44
+ @response.server_error?.should be true
45
+ end
46
+ end
47
+
48
+ describe "with a server error HTTP response _and_ SOAP fault message" do
49
+ before do
50
+ http_response = Net::HTTPServerError.new('1.1', '500', 'Internal Server Error')
51
+ http_response.stub(:body).and_return(%{<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"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Illegal argument. For input string: "100.0"</faultstring></soap:Fault></soap:Body></soap:Envelope>})
52
+ @response = Adyen::API::Response.new(http_response)
53
+ end
54
+
55
+ it "`server_error?` returns that the (HTTP) request did not cause a server error" do
56
+ @response.server_error?.should be false
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,133 @@
1
+ # encoding: UTF-8
2
+ require 'api/spec_helper'
3
+
4
+ module APISpecHelper
5
+ class SOAPClient < Adyen::API::SimpleSOAPClient
6
+ ENDPOINT_URI = 'https://%s.example.com/soap/Action'
7
+ end
8
+ end
9
+
10
+ describe Adyen::API::SimpleSOAPClient do
11
+ include APISpecHelper
12
+
13
+ before do
14
+ @client = APISpecHelper::SOAPClient.new(:reference => 'order-id')
15
+ end
16
+
17
+ it "returns the endpoint, for the current environment, from the ENDPOINT_URI constant" do
18
+ uri = APISpecHelper::SOAPClient.endpoint
19
+ uri.scheme.should == 'https'
20
+ uri.host.should == 'test.example.com'
21
+ uri.path.should == '/soap/Action'
22
+ end
23
+
24
+ it "initializes with the given parameters" do
25
+ @client.params[:reference].should == 'order-id'
26
+ end
27
+
28
+ it "merges the default parameters with the given ones" do
29
+ @client.params[:merchant_account].should == 'SuperShopper'
30
+ end
31
+
32
+ describe "call_webservice_action" do
33
+ before do
34
+ stub_net_http(AUTHORISE_RESPONSE)
35
+ @response = @client.call_webservice_action('Action', '<bananas>Yes, please</bananas>', Adyen::API::Response)
36
+ @request, @post = Net::HTTP.posted
37
+ end
38
+
39
+ after do
40
+ Net::HTTP.stubbing_enabled = false
41
+ end
42
+
43
+ it "posts to the class's endpoint" do
44
+ endpoint = APISpecHelper::SOAPClient.endpoint
45
+ @request.host.should == endpoint.host
46
+ @request.port.should == endpoint.port
47
+ @post.path.should == endpoint.path
48
+ end
49
+
50
+ it "makes a request over SSL" do
51
+ @request.use_ssl?.should be true
52
+ end
53
+
54
+ it "verifies certificates" do
55
+ File.should exist(Adyen::API::SimpleSOAPClient::CACERT)
56
+ @request.ca_file.should == Adyen::API::SimpleSOAPClient::CACERT
57
+ @request.verify_mode.should == OpenSSL::SSL::VERIFY_PEER
58
+ end
59
+
60
+ it "uses basic-authentication with the credentials set on the Adyen::API module" do
61
+ username, password = @post.assigned_basic_auth
62
+ username.should == 'SuperShopper'
63
+ password.should == 'secret'
64
+ end
65
+
66
+ it "sends the proper headers" do
67
+ @post.header.should include(
68
+ 'accept' => ['text/xml'],
69
+ 'content-type' => ['text/xml; charset=utf-8'],
70
+ 'soapaction' => ['Action']
71
+ )
72
+ end
73
+
74
+ it "returns an Adyen::API::Response instance" do
75
+ @response.should be_instance_of(Adyen::API::Response)
76
+ @response.xml_querier.to_s.rstrip.should == AUTHORISE_RESPONSE.rstrip
77
+ end
78
+
79
+ [
80
+ [
81
+ "[401 Bad request] A client",
82
+ Net::HTTPBadRequest.new('1.1', '401', 'Bad request'),
83
+ Adyen::API::SimpleSOAPClient::ClientError
84
+ ]
85
+ ].each do |label, response, expected_exception|
86
+ it "raises when the HTTP response is a subclass of #{response.class.name}" do
87
+ response.stub(:body).and_return(%{<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"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Illegal argument. For input string: "100.0"</faultstring></soap:Fault></soap:Body></soap:Envelope>})
88
+ Net::HTTP.stubbed_response = response
89
+
90
+ exception = nil
91
+ begin
92
+ @client.call_webservice_action('Action', '<bananas>Yes, please</bananas>', Adyen::API::Response)
93
+ rescue expected_exception => e
94
+ exception = e
95
+ end
96
+ exception.message.should == %{#{label} error occurred while calling SOAP action `Action' on endpoint `https://test.example.com/soap/Action'. Fault message: Illegal argument. For input string: "100.0".}
97
+ end
98
+ end
99
+
100
+ describe 'server error' do
101
+ [
102
+ ["[500 Internal Server Error] A server", Net::HTTPBadGateway.new('1.1', '500', 'Internal Server Error')],
103
+ ["[501 Not Implemented] A server", Net::HTTPBadGateway.new('1.1', '501', 'Not Implemented')],
104
+ ["[502 Bad Gateway] A server", Net::HTTPBadGateway.new('1.1', '502', 'Bad Gateway')],
105
+ ["[503 Service Unavailable] A server", Net::HTTPBadGateway.new('1.1', '503', 'Service Unavailable')],
106
+ ["[504 Gateway Timeout] A server", Net::HTTPBadGateway.new('1.1', '504', 'Gateway Timeout')],
107
+ ["[505 HTTP Version Not Supported] A server", Net::HTTPBadGateway.new('1.1', '505', 'HTTP Version Not Supported')],
108
+ ].each do |label, response|
109
+ it "is raised when the HTTP response is a `real` server error by status code" do
110
+ response.stub(:body).and_return(%{<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"><soap:Body></soap:Body></soap:Envelope>})
111
+ Net::HTTP.stubbed_response = response
112
+
113
+ exception = nil
114
+ begin
115
+ @client.call_webservice_action('Action', '<bananas>Yes, please</bananas>', Adyen::API::Response)
116
+ rescue Adyen::API::SimpleSOAPClient::ServerError => e
117
+ exception = e
118
+ end
119
+ exception.message.should == %{#{label} error occurred while calling SOAP action `Action' on endpoint `https://test.example.com/soap/Action'.}
120
+ end
121
+ end
122
+
123
+ it "is not raised when the HTTP response has a 500 status code with a fault message" do
124
+ response = Net::HTTPServerError.new('1.1', '500', 'Internal Server Error')
125
+ response.stub(:body).and_return(%{<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"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Illegal argument. For input string: "100.0"</faultstring></soap:Fault></soap:Body></soap:Envelope>})
126
+
127
+ lambda do
128
+ @client.call_webservice_action('Action', '<bananas>Yes, please</bananas>', Adyen::API::Response)
129
+ end.should_not raise_error
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,463 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ require 'adyen/api'
5
+
6
+ require 'nokogiri'
7
+ require 'rexml/document'
8
+
9
+ Adyen.configuration.default_api_params = { :merchant_account => 'SuperShopper' }
10
+ Adyen.configuration.api_username = 'SuperShopper'
11
+ Adyen.configuration.api_password = 'secret'
12
+
13
+ module Net
14
+ class HTTP
15
+ class Post
16
+ attr_reader :header
17
+ attr_reader :assigned_basic_auth
18
+
19
+ alias old_basic_auth basic_auth
20
+ def basic_auth(username, password)
21
+ if Net::HTTP.stubbing_enabled
22
+ @assigned_basic_auth = [username, password]
23
+ else
24
+ old_basic_auth(username, password)
25
+ end
26
+ end
27
+
28
+ def soap_action
29
+ header['soapaction'].first
30
+ end
31
+ end
32
+
33
+ class << self
34
+ attr_accessor :stubbing_enabled, :posted, :stubbed_response
35
+
36
+ def stubbing_enabled=(enabled)
37
+ reset! if @stubbing_enabled = enabled
38
+ end
39
+
40
+ def reset!
41
+ @posted = nil
42
+ @stubbed_response = nil
43
+ end
44
+ end
45
+
46
+ def host
47
+ @address
48
+ end
49
+
50
+ alias old_start start
51
+ def start(&block)
52
+ Net::HTTP.stubbing_enabled ? yield(self) : old_start(&block)
53
+ end
54
+
55
+ alias old_request request
56
+ def request(request)
57
+ if Net::HTTP.stubbing_enabled
58
+ self.class.posted = [self, request]
59
+ self.class.stubbed_response
60
+ else
61
+ old_request(request)
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ module Adyen
68
+ module API
69
+ class PaymentService
70
+ public :authorise_payment_request_body,
71
+ :authorise_recurring_payment_request_body,
72
+ :authorise_one_click_payment_request_body,
73
+ :capture_request_body, :refund_request_body,
74
+ :cancel_or_refund_request_body,
75
+ :cancel_request_body
76
+ end
77
+
78
+ class RecurringService
79
+ public :list_request_body, :disable_request_body
80
+ end
81
+ end
82
+ end
83
+
84
+ module APISpecHelper
85
+ def node_for_current_object_and_method
86
+ Adyen::API::XMLQuerier.xml(@object.send(@method))
87
+ end
88
+
89
+ def xpath(query, &block)
90
+ node_for_current_method.xpath(query, &block)
91
+ end
92
+
93
+ def text(query)
94
+ node_for_current_method.text(query)
95
+ end
96
+
97
+ def stub_net_http(response_body)
98
+ Net::HTTP.stubbing_enabled = true
99
+ response = Net::HTTPOK.new('1.1', '200', 'OK')
100
+ response.stub(:body).and_return(response_body)
101
+ Net::HTTP.stubbed_response = response
102
+ end
103
+
104
+ def self.included(klass)
105
+ klass.extend ClassMethods
106
+ end
107
+
108
+ module ClassMethods
109
+ def for_each_xml_backend(&block)
110
+ backends = [Adyen::API::XMLQuerier::NokogiriBackend, Adyen::API::XMLQuerier::REXMLBackend]
111
+ backends.each do |xml_backend|
112
+ describe "with a #{xml_backend} backend" do
113
+ before { Adyen::API::XMLQuerier.stub(:default_backend => xml_backend.new) }
114
+ instance_eval(&block)
115
+ end
116
+ end
117
+ end
118
+
119
+ def it_should_have_shortcut_methods_for_params_on_the_response
120
+ it "provides shortcut methods, on the response object, for all entries in the #params hash" do
121
+ @response.params.each do |key, value|
122
+ @response.send(key).should == value
123
+ end
124
+ end
125
+ end
126
+
127
+ def it_should_return_params_for_each_xml_backend(params)
128
+ for_each_xml_backend do
129
+ it "returns a hash with parsed response details" do
130
+ @object.send(@method).params.should == params
131
+ end
132
+ end
133
+ end
134
+
135
+ def it_should_validate_request_parameters(*params)
136
+ params.each do |param|
137
+ case param
138
+ when Symbol
139
+ it_should_validate_request_param(param) { @object.params[param] = '' }
140
+ when Hash
141
+ param.each do |name, attrs|
142
+ it_should_validate_request_param(name) { @object.params[name] = nil }
143
+ attrs.each do |attr|
144
+ it_should_validate_request_param("#{name} => :#{attr}") { @object.params[name][attr] = nil }
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ def it_should_validate_request_param(name, &block)
152
+ it "validates the `#{name}' request parameter" do
153
+ instance_eval &block
154
+ lambda { @object.send(@method) }.should raise_error(ArgumentError)
155
+ end
156
+ end
157
+
158
+ def describe_response_from(method, response, soap_action = 'authorise', &block)
159
+ describe(method) do
160
+ before do
161
+ stub_net_http(response)
162
+ @method = method
163
+ @object.params.merge!(:psp_reference => '9876543210987654')
164
+ @response = @object.send(@method)
165
+ @request, @post = Net::HTTP.posted
166
+ end
167
+
168
+ after do
169
+ Net::HTTP.stubbing_enabled = false
170
+ end
171
+
172
+ it "posts the body generated for the given parameters" do
173
+ @post.body.should == Adyen::API::SimpleSOAPClient::ENVELOPE % @object.send("#{@method}_request_body")
174
+ end
175
+
176
+ it "posts to the correct SOAP action" do
177
+ @post.soap_action.should == soap_action
178
+ end
179
+
180
+ it_should_have_shortcut_methods_for_params_on_the_response
181
+
182
+ instance_eval(&block)
183
+ end
184
+ end
185
+
186
+ def describe_request_body_of(method, xpath = nil, &block)
187
+ method = "#{method}_request_body"
188
+ describe(method) do
189
+ before { @method = method }
190
+ if xpath
191
+ define_method(:node_for_current_method) do
192
+ node_for_current_object_and_method.xpath(xpath)
193
+ end
194
+ end
195
+ instance_eval(&block)
196
+ end
197
+ end
198
+
199
+ def describe_modification_request_body_of(method, camelized_method = nil, &block)
200
+ describe_request_body_of method, "//payment:#{camelized_method || method}/payment:modificationRequest" do
201
+ before do
202
+ @payment.params[:psp_reference] = 'original-psp-reference'
203
+ end
204
+
205
+ it "includes the merchant account" do
206
+ text('./payment:merchantAccount').should == 'SuperShopper'
207
+ end
208
+
209
+ it "includes the payment (PSP) reference of the payment to refund" do
210
+ text('./payment:originalReference').should == 'original-psp-reference'
211
+ end
212
+
213
+ instance_eval(&block) if block_given?
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ AUTHORISE_RESPONSE = <<EOS
220
+ <?xml version="1.0" encoding="UTF-8"?>
221
+ <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">
222
+ <soap:Body>
223
+ <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
224
+ <ns1:paymentResult>
225
+ <additionalData xmlns="http://payment.services.adyen.com">
226
+ <entry>
227
+ <key xsi:type="xsd:string">cardSummary</key>
228
+ <value xsi:type="xsd:string">1111</value>
229
+ </entry>
230
+ </additionalData>
231
+ <authCode xmlns="http://payment.services.adyen.com">1234</authCode>
232
+ <dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
233
+ <dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
234
+ <fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
235
+ <issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
236
+ <md xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
237
+ <paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
238
+ <pspReference xmlns="http://payment.services.adyen.com">9876543210987654</pspReference>
239
+ <refusalReason xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
240
+ <resultCode xmlns="http://payment.services.adyen.com">Authorised</resultCode>
241
+ </ns1:paymentResult>
242
+ </ns1:authoriseResponse>
243
+ </soap:Body>
244
+ </soap:Envelope>
245
+ EOS
246
+
247
+ AUTHORISATION_DECLINED_RESPONSE = <<EOS
248
+ <?xml version="1.0" encoding="UTF-8"?>
249
+ <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">
250
+ <soap:Body>
251
+ <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
252
+ <ns1:paymentResult>
253
+ <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
254
+ <authCode xmlns="http://payment.services.adyen.com">1234</authCode>
255
+ <dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
256
+ <dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
257
+ <fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
258
+ <issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
259
+ <md xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
260
+ <paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
261
+ <pspReference xmlns="http://payment.services.adyen.com">9876543210987654</pspReference>
262
+ <refusalReason xmlns="http://payment.services.adyen.com">You need to actually own money.</refusalReason>
263
+ <resultCode xmlns="http://payment.services.adyen.com">Refused</resultCode>
264
+ </ns1:paymentResult>
265
+ </ns1:authoriseResponse>
266
+ </soap:Body>
267
+ </soap:Envelope>
268
+ EOS
269
+
270
+ AUTHORISE_REQUEST_INVALID_RESPONSE = <<EOS
271
+ <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">
272
+ <soap:Body>
273
+ <soap:Fault>
274
+ <faultcode>soap:Server</faultcode>
275
+ <faultstring>%s</faultstring>
276
+ </soap:Fault>
277
+ </soap:Body>
278
+ </soap:Envelope>
279
+ EOS
280
+
281
+ AUTHORISE_REQUEST_REFUSED_RESPONSE = <<EOS
282
+ <?xml version="1.0" encoding="UTF-8"?>
283
+ <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">
284
+ <soap:Body>
285
+ <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
286
+ <ns1:paymentResult>
287
+ <refusalReason xmlns="http://payment.services.adyen.com">You need to actually own money.</refusalReason>
288
+ <resultCode xmlns="http://payment.services.adyen.com">Refused</resultCode>
289
+ </ns1:paymentResult>
290
+ </ns1:authoriseResponse>
291
+ </soap:Body>
292
+ </soap:Envelope>
293
+ EOS
294
+
295
+
296
+ LIST_RESPONSE = <<EOS
297
+ <?xml version="1.0"?>
298
+ <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">
299
+ <soap:Body>
300
+ <ns1:listRecurringDetailsResponse xmlns:ns1="http://recurring.services.adyen.com">
301
+ <ns1:result xmlns:ns2="http://payment.services.adyen.com">
302
+ <ns1:creationDate>2009-10-27T11:26:22.203+01:00</ns1:creationDate>
303
+ <details xmlns="http://recurring.services.adyen.com">
304
+ <RecurringDetail>
305
+ <bank xsi:nil="true"/>
306
+ <card>
307
+ <cvc xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
308
+ <expiryMonth xmlns="http://payment.services.adyen.com">12</expiryMonth>
309
+ <expiryYear xmlns="http://payment.services.adyen.com">2012</expiryYear>
310
+ <holderName xmlns="http://payment.services.adyen.com">S. Hopper</holderName>
311
+ <issueNumber xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
312
+ <number xmlns="http://payment.services.adyen.com">1111</number>
313
+ <startMonth xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
314
+ <startYear xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
315
+ </card>
316
+ <creationDate>2009-10-27T11:50:12.178+01:00</creationDate>
317
+ <elv xsi:nil="true"/>
318
+ <name/>
319
+ <recurringDetailReference>RecurringDetailReference1</recurringDetailReference>
320
+ <variant>mc</variant>
321
+ </RecurringDetail>
322
+ <RecurringDetail>
323
+ <bank>
324
+ <bankAccountNumber xmlns="http://payment.services.adyen.com">123456789</bankAccountNumber>
325
+ <bankLocationId xmlns="http://payment.services.adyen.com">bank-location-id</bankLocationId>
326
+ <bankName xmlns="http://payment.services.adyen.com">AnyBank</bankName>
327
+ <bic xmlns="http://payment.services.adyen.com">BBBBCCLLbbb</bic>
328
+ <countryCode xmlns="http://payment.services.adyen.com">NL</countryCode>
329
+ <iban xmlns="http://payment.services.adyen.com">NL69PSTB0001234567</iban>
330
+ <ownerName xmlns="http://payment.services.adyen.com">S. Hopper</ownerName>
331
+ </bank>
332
+ <card xsi:nil="true"/>
333
+ <creationDate>2009-10-27T11:26:22.216+01:00</creationDate>
334
+ <elv xsi:nil="true"/>
335
+ <name/>
336
+ <recurringDetailReference>RecurringDetailReference2</recurringDetailReference>
337
+ <variant>IDEAL</variant>
338
+ </RecurringDetail>
339
+ <RecurringDetail>
340
+ <card xsi:nil="true"/>
341
+ <bank xsi:nil="true"/>
342
+ <elv>
343
+ <accountHolderName xmlns="http://payment.services.adyen.com">S. Hopper</accountHolderName>
344
+ <bankAccountNumber xmlns="http://payment.services.adyen.com">1234567890</bankAccountNumber>
345
+ <bankLocation xmlns="http://payment.services.adyen.com">Berlin</bankLocation>
346
+ <bankLocationId xmlns="http://payment.services.adyen.com">12345678</bankLocationId>
347
+ <bankName xmlns="http://payment.services.adyen.com">TestBank</bankName>
348
+ </elv>
349
+ <creationDate>2009-10-27T11:26:22.216+01:00</creationDate>
350
+ <name/>
351
+ <recurringDetailReference>RecurringDetailReference3</recurringDetailReference>
352
+ <variant>elv</variant>
353
+ </RecurringDetail>
354
+ </details>
355
+ <ns1:lastKnownShopperEmail>s.hopper@example.com</ns1:lastKnownShopperEmail>
356
+ <ns1:shopperReference>user-id</ns1:shopperReference>
357
+ </ns1:result>
358
+ </ns1:listRecurringDetailsResponse>
359
+ </soap:Body>
360
+ </soap:Envelope>
361
+ EOS
362
+
363
+ LIST_EMPTY_RESPONSE = <<EOS
364
+ <?xml version="1.0"?>
365
+ <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">
366
+ <soap:Body>
367
+ <ns1:listRecurringDetailsResponse xmlns:ns1="http://recurring.services.adyen.com">
368
+ <ns1:result>
369
+ <details xmlns="http://recurring.services.adyen.com"/>
370
+ <lastKnownShopperEmail xmlns="http://recurring.services.adyen.com" xsi:nil="true"/>
371
+ <shopperReference xmlns="http://recurring.services.adyen.com" xsi:nil="true"/>
372
+ </ns1:result>
373
+ </ns1:listRecurringDetailsResponse>
374
+ </soap:Body>
375
+ </soap:Envelope>
376
+ EOS
377
+
378
+ DISABLE_RESPONSE = <<EOS
379
+ <?xml version="1.0"?>
380
+ <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">
381
+ <soap:Body>
382
+ <ns1:disableResponse xmlns:ns1="http://recurring.services.adyen.com">
383
+ <ns1:result>
384
+ <response xmlns="http://recurring.services.adyen.com">
385
+ %s
386
+ </response>
387
+ </ns1:result>
388
+ </ns1:disableResponse>
389
+ </soap:Body>
390
+ </soap:Envelope>
391
+ EOS
392
+
393
+ REFUND_RESPONSE = <<EOS
394
+ <?xml version="1.0"?>
395
+ <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">
396
+ <soap:Body>
397
+ <ns1:refundResponse xmlns:ns1="http://payment.services.adyen.com">
398
+ <ns1:refundResult>
399
+ <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
400
+ <pspReference xmlns="http://payment.services.adyen.com">8512865475512126</pspReference>
401
+ <response xmlns="http://payment.services.adyen.com">%s</response>
402
+ </ns1:refundResult>
403
+ </ns1:refundResponse>
404
+ </soap:Body>
405
+ </soap:Envelope>
406
+ EOS
407
+
408
+ CANCEL_OR_REFUND_RESPONSE = <<EOS
409
+ <?xml version="1.0"?>
410
+ <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">
411
+ <soap:Body>
412
+ <ns1:cancelOrRefundResponse xmlns:ns1="http://payment.services.adyen.com">
413
+ <ns1:cancelOrRefundResult>
414
+ <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
415
+ <pspReference xmlns="http://payment.services.adyen.com">8512865521218306</pspReference>
416
+ <response xmlns="http://payment.services.adyen.com">%s</response>
417
+ </ns1:cancelOrRefundResult>
418
+ </ns1:cancelOrRefundResponse>
419
+ </soap:Body>
420
+ </soap:Envelope>
421
+ EOS
422
+
423
+ CANCEL_RESPONSE = <<EOS
424
+ <?xml version="1.0"?>
425
+ <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">
426
+ <soap:Body>
427
+ <ns1:cancelResponse xmlns:ns1="http://payment.services.adyen.com">
428
+ <ns1:cancelResult>
429
+ <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
430
+ <pspReference xmlns="http://payment.services.adyen.com">8612865544848013</pspReference>
431
+ <response xmlns="http://payment.services.adyen.com">%s</response>
432
+ </ns1:cancelResult>
433
+ </ns1:cancelResponse>
434
+ </soap:Body>
435
+ </soap:Envelope>
436
+ EOS
437
+
438
+ CAPTURE_RESPONSE = <<EOS
439
+ <?xml version="1.0"?>
440
+ <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">
441
+ <soap:Body>
442
+ <ns1:captureResponse xmlns:ns1="http://payment.services.adyen.com">
443
+ <ns1:captureResult>
444
+ <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
445
+ <pspReference xmlns="http://payment.services.adyen.com">8512867956198946</pspReference>
446
+ <response xmlns="http://payment.services.adyen.com">%s</response>
447
+ </ns1:captureResult>
448
+ </ns1:captureResponse>
449
+ </soap:Body>
450
+ </soap:Envelope>
451
+ EOS
452
+
453
+ BILLET_RECEIVED_RESPONSE = <<EOS
454
+ <?xml version="1.0"?>
455
+ <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">
456
+ <soap:Body>
457
+ <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com"><ns1:paymentResult><additionalData xmlns="http://payment.services.adyen.com"><entry><key xsi:type="xsd:string">boletobancario.url</key><value xsi:type="xsd:string">https://test.adyen.com/hpp/generationBoleto.shtml?data=AgABAQBdYDe9OqdseA79Rfexm2Lz8fRQ1bWqkLhBCf1fHhQEif7bsRKi0otq%2B1ekMAdMIZUiVXeR3QFrAOA8Zy4tpiNLhkMq6f7W2zFqYhVWrByqxQnbQTYuX2FWI7tsu7Vb0MnyOvFfFdFtaxzImZYCli%2BMrqaAJ5HI9ap3egeqBQIsRI%2Fj0zWsu2EGN16lGbwFOLyxl%2By0Pc5jazTo8rnBA7OVPGDIu7Qt%2F2DYIMcB6PXou5W3aJoTC4SldhNdobVqgWUtES8NsWdOYbLGa6I%2BjSwEFXvxyTXwtw4J2E%2BE7ux1UhBiZRj66lMbcvaYlfnR2xWbA%2BKmdLrVvuXTroEHKQ%2B1C%2FuyGuiOk3SmGq6TMgOyCEt%2BmG%2Bq6z5jDi%2BnYLtlLQU4ccMOujgWMfGkViC%2FXDUlqYjKbn8NHwPwoPcelpf1zCDCe%2Fvu6NBTVQbEXbE0oV0j2MT1tLlMdf08iUsDThuQ3MlJbE8VbTMlttOFqoyXhBjepQ42C1eXfswSz1gsZlHanBCTiw1pB69vkvfWPf5IdUSx1cpEr9LJ9PSz%2FeHxEhq%2B8ZdWzrybXqRbEl2mUjLeyhMNuiE%3D</value></entry><entry><key xsi:type="xsd:string">boletobancario.data</key><value xsi:type="xsd:string">AgABAQBdYDe9OqdseA79Rfexm2Lz8fRQ1bWqkLhBCf1fHhQEif7bsRKi0otq+1ekMAdMIZUiVXeR3QFrAOA8Zy4tpiNLhkMq6f7W2zFqYhVWrByqxQnbQTYuX2FWI7tsu7Vb0MnyOvFfFdFtaxzImZYCli+MrqaAJ5HI9ap3egeqBQIsRI/j0zWsu2EGN16lGbwFOLyxl+y0Pc5jazTo8rnBA7OVPGDIu7Qt/2DYIMcB6PXou5W3aJoTC4SldhNdobVqgWUtES8NsWdOYbLGa6I+jSwEFXvxyTXwtw4J2E+E7ux1UhBiZRj66lMbcvaYlfnR2xWbA+KmdLrVvuXTroEHKQ+1C/uyGuiOk3SmGq6TMgOyCEt+mG+q6z5jDi+nYLtlLQU4ccMOujgWMfGkViC/XDUlqYjKbn8NHwPwoPcelpf1zCDCe/vu6NBTVQbEXbE0oV0j2MT1tLlMdf08iUsDThuQ3MlJbE8VbTMlttOFqoyXhBjepQ42C1eXfswSz1gsZlHanBCTiw1pB69vkvfWPf5IdUSx1cpEr9LJ9PSz/eHxEhq+8ZdWzrybXqRbEl2mUjLeyhMNuiE=</value></entry><entry><key xsi:type="xsd:string">boletobancario.expirationDate</key><value xsi:type="xsd:string">2014-07-17</value></entry><entry><key xsi:type="xsd:string">boletobancario.dueDate</key><value xsi:type="xsd:string">2014-07-02</value></entry></additionalData><authCode xmlns="http://payment.services.adyen.com" xsi:nil="true" /><dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true" /><dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true" /><fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true" /><issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true" /><md xmlns="http://payment.services.adyen.com" xsi:nil="true" /><paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true" /><pspReference xmlns="http://payment.services.adyen.com">8814038837489129</pspReference><refusalReason xmlns="http://payment.services.adyen.com" xsi:nil="true" /><resultCode xmlns="http://payment.services.adyen.com">Received</resultCode></ns1:paymentResult></ns1:authoriseResponse></soap:Body></soap:Envelope>
458
+ EOS
459
+
460
+ BILLET_REFUSED_RESPONSE = <<EOS
461
+ <?xml version="1.0"?>
462
+ <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'><soap:Body><ns1:authoriseResponse xmlns:ns1='http://payment.services.adyen.com'><ns1:paymentResult><additionalData xmlns='http://payment.services.adyen.com' xsi:nil='true' /><authCode xmlns='http://payment.services.adyen.com' xsi:nil='true' /><dccAmount xmlns='http://payment.services.adyen.com' xsi:nil='true' /><dccSignature xmlns='http://payment.services.adyen.com' xsi:nil='true' /><fraudResult xmlns='http://payment.services.adyen.com' xsi:nil='true' /><issuerUrl xmlns='http://payment.services.adyen.com' xsi:nil='true' /><md xmlns='http://payment.services.adyen.com' xsi:nil='true' /><paRequest xmlns='http://payment.services.adyen.com' xsi:nil='true' /><pspReference xmlns='http://payment.services.adyen.com'>8514038928235061</pspReference><refusalReason xmlns='http://payment.services.adyen.com'>102 Unable to determine variant</refusalReason><resultCode xmlns='http://payment.services.adyen.com'>Refused</resultCode></ns1:paymentResult></ns1:authoriseResponse></soap:Body></soap:Envelope>
463
+ EOS