adyen 0.3.8 → 1.0.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 (46) hide show
  1. data/.gitignore +4 -0
  2. data/.kick +35 -0
  3. data/LICENSE +3 -2
  4. data/README.rdoc +8 -4
  5. data/Rakefile +10 -0
  6. data/TODO +14 -4
  7. data/adyen.gemspec +9 -15
  8. data/lib/adyen.rb +10 -59
  9. data/lib/adyen/api.rb +281 -0
  10. data/lib/adyen/api/cacert.pem +3509 -0
  11. data/lib/adyen/api/payment_service.rb +258 -0
  12. data/lib/adyen/api/recurring_service.rb +126 -0
  13. data/lib/adyen/api/response.rb +54 -0
  14. data/lib/adyen/api/simple_soap_client.rb +118 -0
  15. data/lib/adyen/api/templates/payment_service.rb +103 -0
  16. data/lib/adyen/api/templates/recurring_service.rb +34 -0
  17. data/lib/adyen/api/test_helpers.rb +133 -0
  18. data/lib/adyen/api/xml_querier.rb +94 -0
  19. data/lib/adyen/configuration.rb +139 -0
  20. data/lib/adyen/form.rb +37 -109
  21. data/lib/adyen/formatter.rb +0 -10
  22. data/lib/adyen/matchers.rb +1 -1
  23. data/lib/adyen/notification_generator.rb +30 -0
  24. data/lib/adyen/railtie.rb +13 -0
  25. data/lib/adyen/templates/notification_migration.rb +29 -0
  26. data/lib/adyen/templates/notification_model.rb +70 -0
  27. data/spec/adyen_spec.rb +3 -45
  28. data/spec/api/api_spec.rb +139 -0
  29. data/spec/api/payment_service_spec.rb +439 -0
  30. data/spec/api/recurring_service_spec.rb +105 -0
  31. data/spec/api/response_spec.rb +35 -0
  32. data/spec/api/simple_soap_client_spec.rb +91 -0
  33. data/spec/api/spec_helper.rb +417 -0
  34. data/spec/api/test_helpers_spec.rb +83 -0
  35. data/spec/form_spec.rb +27 -23
  36. data/spec/functional/api_spec.rb +90 -0
  37. data/spec/functional/initializer.rb.sample +3 -0
  38. data/spec/spec_helper.rb +5 -5
  39. data/tasks/github-gem.rake +49 -55
  40. data/yard_extensions.rb +16 -0
  41. metadata +63 -82
  42. data/init.rb +0 -1
  43. data/lib/adyen/notification.rb +0 -151
  44. data/lib/adyen/soap.rb +0 -649
  45. data/spec/notification_spec.rb +0 -97
  46. data/spec/soap_spec.rb +0 -340
@@ -0,0 +1,139 @@
1
+ # encoding: UTF-8
2
+ require 'api/spec_helper'
3
+
4
+ describe Adyen::API do
5
+ include APISpecHelper
6
+
7
+ describe "shortcut methods" do
8
+ describe "for the PaymentService" do
9
+ before do
10
+ @payment = mock('PaymentService')
11
+ end
12
+
13
+ def should_map_shortcut_to(method, params)
14
+ Adyen::API::PaymentService.should_receive(:new).with(params).and_return(@payment)
15
+ @payment.should_receive(method)
16
+ end
17
+
18
+ it "performs a `authorise payment' request without enabling :recurring" do
19
+ should_map_shortcut_to(:authorise_payment,
20
+ :reference => 'order-id',
21
+ :amount => { :currency => 'EUR', :value => 1234 },
22
+ :shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
23
+ :card => { :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' },
24
+ :recurring => false
25
+ )
26
+ Adyen::API.authorise_payment('order-id',
27
+ { :currency => 'EUR', :value => 1234 },
28
+ { :reference => 'user-id', :email => 's.hopper@example.com' },
29
+ { :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' }
30
+ )
31
+ end
32
+
33
+ it "performs a `authorise payment' request with enabling :recurring" do
34
+ should_map_shortcut_to(:authorise_payment,
35
+ :reference => 'order-id',
36
+ :amount => { :currency => 'EUR', :value => 1234 },
37
+ :shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
38
+ :card => { :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' },
39
+ :recurring => true
40
+ )
41
+ Adyen::API.authorise_payment('order-id',
42
+ { :currency => 'EUR', :value => 1234 },
43
+ { :reference => 'user-id', :email => 's.hopper@example.com' },
44
+ { :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' },
45
+ true
46
+ )
47
+ end
48
+
49
+ it "performs a `authorise recurring payment' request without specific detail" do
50
+ should_map_shortcut_to(:authorise_recurring_payment,
51
+ :reference => 'order-id',
52
+ :amount => { :currency => 'EUR', :value => 1234 },
53
+ :shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
54
+ :recurring_detail_reference => 'LATEST'
55
+ )
56
+ Adyen::API.authorise_recurring_payment('order-id',
57
+ { :currency => 'EUR', :value => 1234 },
58
+ { :reference => 'user-id', :email => 's.hopper@example.com' }
59
+ )
60
+ end
61
+
62
+ it "performs a `authorise recurring payment' request with specific detail" do
63
+ should_map_shortcut_to(:authorise_recurring_payment,
64
+ :reference => 'order-id',
65
+ :amount => { :currency => 'EUR', :value => 1234 },
66
+ :shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
67
+ :recurring_detail_reference => 'recurring-detail-reference'
68
+ )
69
+ Adyen::API.authorise_recurring_payment('order-id',
70
+ { :currency => 'EUR', :value => 1234 },
71
+ { :reference => 'user-id', :email => 's.hopper@example.com' },
72
+ 'recurring-detail-reference'
73
+ )
74
+ end
75
+
76
+ it "performs a `authorise one-click payment' request with specific detail" do
77
+ should_map_shortcut_to(:authorise_one_click_payment,
78
+ :reference => 'order-id',
79
+ :amount => { :currency => 'EUR', :value => 1234 },
80
+ :shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
81
+ :card => { :cvc => '737' },
82
+ :recurring_detail_reference => 'recurring-detail-reference'
83
+ )
84
+ Adyen::API.authorise_one_click_payment('order-id',
85
+ { :currency => 'EUR', :value => 1234 },
86
+ { :reference => 'user-id', :email => 's.hopper@example.com' },
87
+ '737',
88
+ 'recurring-detail-reference'
89
+ )
90
+ end
91
+
92
+ it "performs a `capture' request" do
93
+ should_map_shortcut_to(:capture, :psp_reference => 'original-psp-reference', :amount => { :currency => 'EUR', :value => '1234' })
94
+ Adyen::API.capture_payment('original-psp-reference', { :currency => 'EUR', :value => '1234' })
95
+ end
96
+
97
+ it "performs a `refund payment' request" do
98
+ should_map_shortcut_to(:refund, :psp_reference => 'original-psp-reference', :amount => { :currency => 'EUR', :value => '1234' })
99
+ Adyen::API.refund_payment('original-psp-reference', { :currency => 'EUR', :value => '1234' })
100
+ end
101
+
102
+ it "performs a `cancel or refund payment' request" do
103
+ should_map_shortcut_to(:cancel_or_refund, :psp_reference => 'original-psp-reference')
104
+ Adyen::API.cancel_or_refund_payment('original-psp-reference')
105
+ end
106
+
107
+ it "performs a `cancel payment' request" do
108
+ should_map_shortcut_to(:cancel, :psp_reference => 'original-psp-reference')
109
+ Adyen::API.cancel_payment('original-psp-reference')
110
+ end
111
+ end
112
+
113
+ describe "for the RecurringService" do
114
+ before do
115
+ @recurring = mock('RecurringService')
116
+ end
117
+
118
+ def should_map_shortcut_to(method, params)
119
+ Adyen::API::RecurringService.should_receive(:new).with(params).and_return(@recurring)
120
+ @recurring.should_receive(method)
121
+ end
122
+
123
+ it "preforms a `list recurring details' request" do
124
+ should_map_shortcut_to(:list, :shopper => { :reference => 'user-id' })
125
+ Adyen::API.list_recurring_details('user-id')
126
+ end
127
+
128
+ it "performs a `disable recurring contract' request for all details" do
129
+ should_map_shortcut_to(:disable, :shopper => { :reference => 'user-id' }, :recurring_detail_reference => nil)
130
+ Adyen::API.disable_recurring_contract('user-id')
131
+ end
132
+
133
+ it "performs a `disable recurring contract' request for a specific detail" do
134
+ should_map_shortcut_to(:disable, :shopper => { :reference => 'user-id' }, :recurring_detail_reference => 'detail-id')
135
+ Adyen::API.disable_recurring_contract('user-id', 'detail-id')
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,439 @@
1
+ # encoding: UTF-8
2
+ require 'api/spec_helper'
3
+
4
+ shared_examples_for "payment requests" do
5
+ it "includes the merchant account handle" do
6
+ text('./payment:merchantAccount').should == 'SuperShopper'
7
+ end
8
+
9
+ it "includes the payment reference of the merchant" do
10
+ text('./payment:reference').should == 'order-id'
11
+ end
12
+
13
+ it "includes the given amount of `currency'" do
14
+ xpath('./payment:amount') do |amount|
15
+ amount.text('./common:currency').should == 'EUR'
16
+ amount.text('./common:value').should == '1234'
17
+ end
18
+ end
19
+
20
+ it "includes the shopper’s details" do
21
+ text('./payment:shopperReference').should == 'user-id'
22
+ text('./payment:shopperEmail').should == 's.hopper@example.com'
23
+ text('./payment:shopperIP').should == '61.294.12.12'
24
+ end
25
+
26
+ it "only includes shopper details for given parameters" do
27
+ # TODO pretty lame, but for now it will do
28
+ unless @method == "authorise_one_click_payment_request_body" || @method == "authorise_recurring_payment_request_body"
29
+ @payment.params[:shopper].delete(:reference)
30
+ xpath('./payment:shopperReference').should be_empty
31
+ @payment.params[:shopper].delete(:email)
32
+ xpath('./payment:shopperEmail').should be_empty
33
+ @payment.params[:shopper].delete(:ip)
34
+ xpath('./payment:shopperIP').should be_empty
35
+ end
36
+ end
37
+
38
+ it "does not include any shopper details if none are given" do
39
+ # TODO pretty lame, but for now it will do
40
+ unless @method == "authorise_one_click_payment_request_body" || @method == "authorise_recurring_payment_request_body"
41
+ @payment.params.delete(:shopper)
42
+ xpath('./payment:shopperReference').should be_empty
43
+ xpath('./payment:shopperEmail').should be_empty
44
+ xpath('./payment:shopperIP').should be_empty
45
+ end
46
+ end
47
+ end
48
+
49
+ shared_examples_for "recurring payment requests" do
50
+ it_should_behave_like "payment requests"
51
+
52
+ it "uses the given recurring detail reference" do
53
+ @payment.params[:recurring_detail_reference] = 'RecurringDetailReference1'
54
+ text('./payment:selectedRecurringDetailReference').should == 'RecurringDetailReference1'
55
+ end
56
+ end
57
+
58
+ describe Adyen::API::PaymentService do
59
+ include APISpecHelper
60
+
61
+ before do
62
+ @params = {
63
+ :reference => 'order-id',
64
+ :amount => {
65
+ :currency => 'EUR',
66
+ :value => '1234',
67
+ },
68
+ :shopper => {
69
+ :email => 's.hopper@example.com',
70
+ :reference => 'user-id',
71
+ :ip => '61.294.12.12',
72
+ },
73
+ :card => {
74
+ :expiry_month => 12,
75
+ :expiry_year => 2012,
76
+ :holder_name => 'Simon わくわく Hopper',
77
+ :number => '4444333322221111',
78
+ :cvc => '737',
79
+ # Maestro UK/Solo only
80
+ #:issue_number => ,
81
+ #:start_month => ,
82
+ #:start_year => ,
83
+ },
84
+ :recurring_detail_reference => 'RecurringDetailReference1'
85
+ }
86
+ @payment = @object = Adyen::API::PaymentService.new(@params)
87
+ end
88
+
89
+ describe_request_body_of :authorise_payment do
90
+ it_should_behave_like "payment requests"
91
+
92
+ it_should_validate_request_parameters :merchant_account,
93
+ :reference,
94
+ :amount => [:currency, :value],
95
+ :card => [:holder_name, :number, :cvc, :expiry_year, :expiry_month]
96
+
97
+ it_should_validate_request_param(:shopper) do
98
+ @payment.params[:recurring] = true
99
+ @payment.params[:shopper] = nil
100
+ end
101
+
102
+ [:reference, :email].each do |attr|
103
+ it_should_validate_request_param(:shopper) do
104
+ @payment.params[:recurring] = true
105
+ @payment.params[:shopper][attr] = ''
106
+ end
107
+ end
108
+
109
+ it "includes the creditcard details" do
110
+ xpath('./payment:card') do |card|
111
+ # there's no reason why Nokogiri should escape these characters, but as long as they're correct
112
+ card.text('./payment:holderName').should == 'Simon わくわく Hopper'
113
+ card.text('./payment:number').should == '4444333322221111'
114
+ card.text('./payment:cvc').should == '737'
115
+ card.text('./payment:expiryMonth').should == '12'
116
+ card.text('./payment:expiryYear').should == '2012'
117
+ end
118
+ end
119
+
120
+ it "formats the creditcard’s expiry month as a two digit number" do
121
+ @payment.params[:card][:expiry_month] = 6
122
+ text('./payment:card/payment:expiryMonth').should == '06'
123
+ end
124
+
125
+ it "includes the necessary recurring and one-click contract info if the `:recurring' param is truthful" do
126
+ xpath('./payment:recurring/payment:contract').should be_empty
127
+ @payment.params[:recurring] = true
128
+ text('./payment:recurring/payment:contract').should == 'RECURRING,ONECLICK'
129
+ end
130
+ end
131
+
132
+ describe_response_from :authorise_payment, AUTHORISE_RESPONSE do
133
+ it_should_return_params_for_each_xml_backend({
134
+ :psp_reference => '9876543210987654',
135
+ :result_code => 'Authorised',
136
+ :auth_code => '1234',
137
+ :refusal_reason => ''
138
+ })
139
+
140
+ describe "with a authorized response" do
141
+ it "returns that the request was authorised" do
142
+ @response.should be_success
143
+ @response.should be_authorized
144
+ end
145
+ end
146
+
147
+ describe "with a `declined' response" do
148
+ before do
149
+ stub_net_http(AUTHORISATION_DECLINED_RESPONSE)
150
+ @response = @payment.authorise_payment
151
+ end
152
+
153
+ it "returns that the request was not authorised" do
154
+ @response.should_not be_success
155
+ @response.should_not be_authorized
156
+ end
157
+ end
158
+
159
+ describe "with a `invalid' response" do
160
+ before do
161
+ stub_net_http(AUTHORISE_REQUEST_INVALID_RESPONSE % 'validation 101 Invalid card number')
162
+ @response = @payment.authorise_payment
163
+ end
164
+
165
+ it "returns that the request was not authorised" do
166
+ @response.should_not be_success
167
+ @response.should_not be_authorized
168
+ end
169
+
170
+ it "it returns that the request was invalid" do
171
+ @response.should be_invalid_request
172
+ end
173
+
174
+ it "returns the fault message from #refusal_reason" do
175
+ @response.refusal_reason.should == 'validation 101 Invalid card number'
176
+ @response.params[:refusal_reason].should == 'validation 101 Invalid card number'
177
+ end
178
+
179
+ it "returns creditcard validation errors" do
180
+ [
181
+ ["validation 101 Invalid card number", [:number, 'is not a valid creditcard number']],
182
+ ["validation 103 CVC is not the right length", [:cvc, 'is not the right length']],
183
+ ["validation 128 Card Holder Missing", [:holder_name, 'can\'t be blank']],
184
+ ["validation Couldn't parse expiry year", [:expiry_year, 'could not be recognized']],
185
+ ["validation Expiry month should be between 1 and 12 inclusive", [:expiry_month, 'could not be recognized']],
186
+ ].each do |message, error|
187
+ response_with_fault_message(message).error.should == error
188
+ end
189
+ end
190
+
191
+ it "returns any other fault messages on `base'" do
192
+ message = "validation 130 Reference Missing"
193
+ response_with_fault_message(message).error.should == [:base, message]
194
+ end
195
+
196
+ it "prepends the error attribute with the given prefix, except for :base" do
197
+ [
198
+ ["validation 101 Invalid card number", [:card_number, 'is not a valid creditcard number']],
199
+ ["validation 130 Reference Missing", [:base, "validation 130 Reference Missing"]],
200
+ ].each do |message, error|
201
+ response_with_fault_message(message).error(:card).should == error
202
+ end
203
+ end
204
+
205
+ it "returns the original message corresponding to the given attribute and message" do
206
+ [
207
+ ["validation 101 Invalid card number", [:number, 'is not a valid creditcard number']],
208
+ ["validation 103 CVC is not the right length", [:cvc, 'is not the right length']],
209
+ ["validation 128 Card Holder Missing", [:holder_name, 'can\'t be blank']],
210
+ ["validation Couldn't parse expiry year", [:expiry_year, 'could not be recognized']],
211
+ ["validation Expiry month should be between 1 and 12 inclusive", [:expiry_month, 'could not be recognized']],
212
+ ["validation 130 Reference Missing", [:base, 'validation 130 Reference Missing']],
213
+ ].each do |expected, attr_and_message|
214
+ Adyen::API::PaymentService::AuthorisationResponse.original_fault_message_for(*attr_and_message).should == expected
215
+ end
216
+ end
217
+
218
+ private
219
+
220
+ def response_with_fault_message(message)
221
+ stub_net_http(AUTHORISE_REQUEST_INVALID_RESPONSE % message)
222
+ @response = @payment.authorise_payment
223
+ end
224
+ end
225
+ end
226
+
227
+ describe_request_body_of :authorise_recurring_payment do
228
+ it_should_behave_like "recurring payment requests"
229
+
230
+ it_should_validate_request_parameters :merchant_account,
231
+ :reference,
232
+ :amount => [:currency, :value],
233
+ :shopper => [:reference, :email]
234
+
235
+ it "includes the contract type, which is `RECURRING'" do
236
+ text('./payment:recurring/payment:contract').should == 'RECURRING'
237
+ end
238
+
239
+ it "uses the latest recurring detail reference, by default" do
240
+ @payment.params[:recurring_detail_reference] = nil
241
+ text('./payment:selectedRecurringDetailReference').should == 'LATEST'
242
+ end
243
+
244
+ it "obviously includes the obligatory self-‘describing’ nonsense parameters" do
245
+ text('./payment:shopperInteraction').should == 'ContAuth'
246
+ end
247
+
248
+ it "does not include any creditcard details" do
249
+ xpath('./payment:card').should be_empty
250
+ end
251
+ end
252
+
253
+ describe_response_from :authorise_recurring_payment, AUTHORISE_RESPONSE do
254
+ it_should_return_params_for_each_xml_backend({
255
+ :psp_reference => '9876543210987654',
256
+ :result_code => 'Authorised',
257
+ :auth_code => '1234',
258
+ :refusal_reason => ''
259
+ })
260
+ end
261
+
262
+ describe_request_body_of :authorise_one_click_payment do
263
+ it_should_behave_like "recurring payment requests"
264
+
265
+ it_should_validate_request_parameters :merchant_account,
266
+ :reference,
267
+ :recurring_detail_reference,
268
+ :amount => [:currency, :value],
269
+ :shopper => [:reference, :email],
270
+ :card => [:cvc]
271
+
272
+ it "includes the contract type, which is `ONECLICK'" do
273
+ text('./payment:recurring/payment:contract').should == 'ONECLICK'
274
+ end
275
+
276
+ it "does not include the self-‘describing’ nonsense parameters" do
277
+ xpath('./payment:shopperInteraction').should be_empty
278
+ end
279
+
280
+ it "includes only the creditcard's CVC code" do
281
+ xpath('./payment:card') do |card|
282
+ card.text('./payment:cvc').should == '737'
283
+
284
+ card.xpath('./payment:holderName').should be_empty
285
+ card.xpath('./payment:number').should be_empty
286
+ card.xpath('./payment:expiryMonth').should be_empty
287
+ card.xpath('./payment:expiryYear').should be_empty
288
+ end
289
+ end
290
+ end
291
+
292
+ describe_response_from :authorise_one_click_payment, AUTHORISE_RESPONSE do
293
+ it_should_return_params_for_each_xml_backend({
294
+ :psp_reference => '9876543210987654',
295
+ :result_code => 'Authorised',
296
+ :auth_code => '1234',
297
+ :refusal_reason => ''
298
+ })
299
+ end
300
+
301
+ describe_modification_request_body_of :capture do
302
+ it_should_validate_request_parameters :merchant_account,
303
+ :psp_reference,
304
+ :amount => [:currency, :value]
305
+
306
+ it "includes the amount to capture" do
307
+ xpath('./payment:modificationAmount') do |amount|
308
+ amount.text('./common:currency').should == 'EUR'
309
+ amount.text('./common:value').should == '1234'
310
+ end
311
+ end
312
+ end
313
+
314
+ describe_response_from :capture, CAPTURE_RESPONSE % '[capture-received]' do
315
+ it_should_return_params_for_each_xml_backend({
316
+ :psp_reference => '8512867956198946',
317
+ :response => '[capture-received]'
318
+ })
319
+
320
+ describe "with a successful response" do
321
+ it "returns that the request was received successfully" do
322
+ @response.should be_success
323
+ end
324
+ end
325
+
326
+ describe "with a failed response" do
327
+ before do
328
+ stub_net_http(CAPTURE_RESPONSE % 'failed')
329
+ @response = @payment.capture
330
+ end
331
+
332
+ it "returns that the request was not received successfully" do
333
+ @response.should_not be_success
334
+ end
335
+ end
336
+ end
337
+
338
+ describe_modification_request_body_of :refund do
339
+ it_should_validate_request_parameters :merchant_account,
340
+ :psp_reference,
341
+ :amount => [:currency, :value]
342
+
343
+ it "includes the amount to refund" do
344
+ xpath('./payment:modificationAmount') do |amount|
345
+ amount.text('./common:currency').should == 'EUR'
346
+ amount.text('./common:value').should == '1234'
347
+ end
348
+ end
349
+ end
350
+
351
+ describe_response_from :refund, REFUND_RESPONSE % '[refund-received]' do
352
+ it_should_return_params_for_each_xml_backend({
353
+ :psp_reference => '8512865475512126',
354
+ :response => '[refund-received]'
355
+ })
356
+
357
+ describe "with a successful response" do
358
+ it "returns that the request was received successfully" do
359
+ @response.should be_success
360
+ end
361
+ end
362
+
363
+ describe "with a failed response" do
364
+ before do
365
+ stub_net_http(REFUND_RESPONSE % 'failed')
366
+ @response = @payment.refund
367
+ end
368
+
369
+ it "returns that the request was not received successfully" do
370
+ @response.should_not be_success
371
+ end
372
+ end
373
+ end
374
+
375
+ describe_modification_request_body_of :cancel_or_refund, 'cancelOrRefund' do
376
+ it_should_validate_request_parameters :merchant_account,
377
+ :psp_reference
378
+ end
379
+
380
+ describe_response_from :cancel_or_refund, CANCEL_OR_REFUND_RESPONSE % '[cancelOrRefund-received]' do
381
+ it_should_return_params_for_each_xml_backend({
382
+ :psp_reference => '8512865521218306',
383
+ :response => '[cancelOrRefund-received]'
384
+ })
385
+
386
+ describe "with a successful response" do
387
+ it "returns that the request was received successfully" do
388
+ @response.should be_success
389
+ end
390
+ end
391
+
392
+ describe "with a failed response" do
393
+ before do
394
+ stub_net_http(CANCEL_OR_REFUND_RESPONSE % 'failed')
395
+ @response = @payment.cancel_or_refund
396
+ end
397
+
398
+ it "returns that the request was not received successfully" do
399
+ @response.should_not be_success
400
+ end
401
+ end
402
+ end
403
+
404
+ describe_modification_request_body_of :cancel do
405
+ it_should_validate_request_parameters :merchant_account,
406
+ :psp_reference
407
+ end
408
+
409
+ describe_response_from :cancel, CANCEL_RESPONSE % '[cancel-received]' do
410
+ it_should_return_params_for_each_xml_backend({
411
+ :psp_reference => '8612865544848013',
412
+ :response => '[cancel-received]'
413
+ })
414
+
415
+ describe "with a successful response" do
416
+ it "returns that the request was received successfully" do
417
+ @response.should be_success
418
+ end
419
+ end
420
+
421
+ describe "with a failed response" do
422
+ before do
423
+ stub_net_http(CANCEL_RESPONSE % 'failed')
424
+ @response = @payment.cancel
425
+ end
426
+
427
+ it "returns that the request was not received successfully" do
428
+ @response.should_not be_success
429
+ end
430
+ end
431
+ end
432
+
433
+ private
434
+
435
+ def node_for_current_method
436
+ node_for_current_object_and_method.xpath('//payment:authorise/payment:paymentRequest')
437
+ end
438
+ end
439
+