fingertips-adyen 0.3.8.20100924 → 0.3.8.20100929

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 (6) hide show
  1. data/TODO +4 -0
  2. data/adyen.gemspec +2 -2
  3. data/lib/adyen/api.rb +256 -162
  4. data/lib/adyen.rb +1 -1
  5. data/spec/api_spec.rb +172 -12
  6. metadata +4 -4
data/TODO CHANGED
@@ -8,3 +8,7 @@
8
8
  * adyen-soap
9
9
  * adyen-railtie
10
10
  * adyen-activemerchant
11
+
12
+ = API
13
+
14
+ * Add Response#errors which returns validation errors from the SOAP API
data/adyen.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'fingertips-adyen'
3
- s.version = "0.3.8.20100924"
4
- s.date = "2010-09-23"
3
+ s.version = "0.3.8.20100929"
4
+ s.date = "2010-09-29"
5
5
 
6
6
  s.summary = "Integrate Adyen payment services in your Ruby on Rails application."
7
7
  s.description = <<-EOS
data/lib/adyen/api.rb CHANGED
@@ -54,7 +54,7 @@ module Adyen
54
54
  @params = API.default_params.merge(params)
55
55
  end
56
56
 
57
- def call_webservice_action(action, data)
57
+ def call_webservice_action(action, data, response_class)
58
58
  endpoint = self.class.endpoint
59
59
 
60
60
  post = Net::HTTP::Post.new(endpoint.path, 'Accept' => 'text/xml', 'Content-Type' => 'text/xml; charset=utf-8', 'SOAPAction' => action)
@@ -67,146 +67,46 @@ module Adyen
67
67
  request.verify_mode = OpenSSL::SSL::VERIFY_PEER
68
68
 
69
69
  request.start do |http|
70
- response = http.request(post)
71
- # TODO: handle not 2xx responses
72
- #p response
73
- XMLQuerier.new(response.body)
70
+ response_class.new(http.request(post))
74
71
  end
75
72
  end
76
73
  end
77
74
 
78
- class PaymentService < SimpleSOAPClient
79
- ENDPOINT_URI = 'https://pal-%s.adyen.com/pal/servlet/soap/Payment'
80
-
81
- def authorise_payment
82
- make_payment_request(authorise_payment_request_body)
83
- end
84
-
85
- def authorise_recurring_payment
86
- make_payment_request(authorise_recurring_payment_request_body)
87
- end
88
-
89
- private
90
-
91
- def make_payment_request(data)
92
- response = call_webservice_action('authorise', data)
93
- response.xpath('//payment:authoriseResponse/payment:paymentResult') do |result|
94
- {
95
- :psp_reference => result.text('./payment:pspReference'),
96
- :result_code => result.text('./payment:resultCode'),
97
- :auth_code => result.text('./payment:authCode'),
98
- :refusal_reason => result.text('./payment:refusalReason')
99
- }
100
- end
101
- end
102
-
103
- def authorise_payment_request_body
104
- content = card_partial
105
- content << RECURRING_PARTIAL if @params[:recurring]
106
- payment_request_body(content)
107
- end
108
-
109
- def authorise_recurring_payment_request_body
110
- content = RECURRING_PAYMENT_BODY_PARTIAL % (@params[:recurring_detail_reference] || 'LATEST')
111
- payment_request_body(content)
112
- end
113
-
114
- def payment_request_body(content)
115
- content << amount_partial
116
- content << shopper_partial if @params[:shopper]
117
- LAYOUT % [@params[:merchant_account], @params[:reference], content]
118
- end
119
-
120
- def amount_partial
121
- AMOUNT_PARTIAL % @params[:amount].values_at(:currency, :value)
122
- end
123
-
124
- def card_partial
125
- card = @params[:card].values_at(:holder_name, :number, :cvc, :expiry_year)
126
- card << @params[:card][:expiry_month].to_i
127
- CARD_PARTIAL % card
128
- end
129
-
130
- def shopper_partial
131
- @params[:shopper].map { |k, v| SHOPPER_PARTIALS[k] % v }.join("\n")
132
- end
133
- end
134
-
135
- class RecurringService < SimpleSOAPClient
136
- ENDPOINT_URI = 'https://pal-%s.adyen.com/pal/servlet/soap/Recurring'
137
-
138
- # TODO: rename to list_details and make shortcut method take the only necessary param
139
- def list
140
- response = call_webservice_action('listRecurringDetails', list_request_body)
141
- response.xpath('//recurring:listRecurringDetailsResponse/recurring:result') do |result|
142
- {
143
- :creation_date => DateTime.parse(result.text('./recurring:creationDate')),
144
- :details => result.xpath('.//recurring:RecurringDetail').map { |node| parse_recurring_detail(node) },
145
- :last_known_shopper_email => result.text('./recurring:lastKnownShopperEmail'),
146
- :shopper_reference => result.text('./recurring:shopperReference')
147
- }
75
+ class Response
76
+ def self.response_attrs(*attrs)
77
+ attrs.each do |attr|
78
+ define_method(attr) { params[attr] }
148
79
  end
149
80
  end
150
81
 
151
- def disable
152
- response = call_webservice_action('disable', disable_request_body)
153
- { :response => response.text('//recurring:disableResponse/recurring:result/recurring:response') }
154
- end
155
-
156
- private
82
+ attr_reader :http_response
157
83
 
158
- def list_request_body
159
- LIST_LAYOUT % [@params[:merchant_account], @params[:shopper][:reference]]
84
+ def initialize(http_response)
85
+ @http_response = http_response
160
86
  end
161
87
 
162
- def disable_request_body
163
- if reference = @params[:recurring_detail_reference]
164
- reference = RECURRING_DETAIL_PARTIAL % reference
165
- end
166
- DISABLE_LAYOUT % [@params[:merchant_account], @params[:shopper][:reference], reference || '']
88
+ # @return [Boolean] Whether or not the request was successful.
89
+ def success?
90
+ !http_failure?
167
91
  end
168
92
 
169
- # @todo add support for elv
170
- def parse_recurring_detail(node)
171
- result = {
172
- :recurring_detail_reference => node.text('./recurring:recurringDetailReference'),
173
- :variant => node.text('./recurring:variant'),
174
- :creation_date => DateTime.parse(node.text('./recurring:creationDate'))
175
- }
176
-
177
- card = node.xpath('./recurring:card')
178
- if card.children.empty?
179
- result[:bank] = parse_bank_details(node.xpath('./recurring:bank'))
180
- else
181
- result[:card] = parse_card_details(card)
182
- end
183
-
184
- result
93
+ # @return [Boolean] Whether or not the HTTP request was a success.
94
+ def http_failure?
95
+ !@http_response.is_a?(Net::HTTPSuccess)
185
96
  end
186
97
 
187
- def parse_card_details(card)
188
- {
189
- :expiry_date => Date.new(card.text('./payment:expiryYear').to_i, card.text('./payment:expiryMonth').to_i, -1),
190
- :holder_name => card.text('./payment:holderName'),
191
- :number => card.text('./payment:number')
192
- }
98
+ def xml_querier
99
+ @xml_querier ||= XMLQuerier.new(@http_response.body)
193
100
  end
194
101
 
195
- def parse_bank_details(bank)
196
- {
197
- :bank_account_number => bank.text('./payment:bankAccountNumber'),
198
- :bank_location_id => bank.text('./payment:bankLocationId'),
199
- :bank_name => bank.text('./payment:bankName'),
200
- :bic => bank.text('./payment:bic'),
201
- :country_code => bank.text('./payment:countryCode'),
202
- :iban => bank.text('./payment:iban'),
203
- :owner_name => bank.text('./payment:ownerName')
204
- }
102
+ def params
103
+ raise "The Adyen::API::Response#params method should be overriden in a subclass."
205
104
  end
206
105
  end
207
106
 
208
107
  class XMLQuerier
209
108
  NS = {
109
+ 'soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
210
110
  'payment' => 'http://payment.services.adyen.com',
211
111
  'recurring' => 'http://recurring.services.adyen.com',
212
112
  'common' => 'http://common.services.adyen.com'
@@ -275,6 +175,197 @@ module Adyen
275
175
  @node.map { |n| self.class.new(n) }.map(&block)
276
176
  end
277
177
  end
178
+
179
+ class PaymentService < SimpleSOAPClient
180
+ ENDPOINT_URI = 'https://pal-%s.adyen.com/pal/servlet/soap/Payment'
181
+
182
+ def authorise_payment
183
+ make_payment_request(authorise_payment_request_body)
184
+ end
185
+
186
+ def authorise_recurring_payment
187
+ make_payment_request(authorise_recurring_payment_request_body)
188
+ end
189
+
190
+ private
191
+
192
+ def make_payment_request(data)
193
+ call_webservice_action('authorise', data, AuthorizationResponse)
194
+ end
195
+
196
+ def authorise_payment_request_body
197
+ content = card_partial
198
+ content << RECURRING_PARTIAL if @params[:recurring]
199
+ payment_request_body(content)
200
+ end
201
+
202
+ def authorise_recurring_payment_request_body
203
+ content = RECURRING_PAYMENT_BODY_PARTIAL % (@params[:recurring_detail_reference] || 'LATEST')
204
+ payment_request_body(content)
205
+ end
206
+
207
+ def payment_request_body(content)
208
+ content << amount_partial
209
+ content << shopper_partial if @params[:shopper]
210
+ LAYOUT % [@params[:merchant_account], @params[:reference], content]
211
+ end
212
+
213
+ def amount_partial
214
+ AMOUNT_PARTIAL % @params[:amount].values_at(:currency, :value)
215
+ end
216
+
217
+ def card_partial
218
+ card = @params[:card].values_at(:holder_name, :number, :cvc, :expiry_year)
219
+ card << @params[:card][:expiry_month].to_i
220
+ CARD_PARTIAL % card
221
+ end
222
+
223
+ def shopper_partial
224
+ @params[:shopper].map { |k, v| SHOPPER_PARTIALS[k] % v }.join("\n")
225
+ end
226
+
227
+ class AuthorizationResponse < Response
228
+ ERRORS = {
229
+ "validation 101 Invalid card number" => [:number, 'is not a valid creditcard number'],
230
+ "validation 103 CVC is not the right length" => [:cvc, 'is not the right length'],
231
+ "validation 128 Card Holder Missing" => [:holder_name, 'can’t be blank'],
232
+ "validation Couldn't parse expiry year" => [:expiry_year, 'could not be recognized'],
233
+ "validation Expiry month should be between 1 and 12 inclusive" => [:expiry_month, 'could not be recognized'],
234
+ }
235
+
236
+ AUTHORISED = 'Authorised'
237
+
238
+ def self.original_fault_message_for(attribute, message)
239
+ if error = ERRORS.find { |_, (a, m)| a == attribute && m == message }
240
+ error.first
241
+ else
242
+ message
243
+ end
244
+ end
245
+
246
+ response_attrs :result_code, :auth_code, :refusal_reason, :psp_reference
247
+
248
+ def success?
249
+ super && params[:result_code] == AUTHORISED
250
+ end
251
+
252
+ alias authorized? success?
253
+
254
+ def invalid_request?
255
+ !fault_message.nil?
256
+ end
257
+
258
+ def error
259
+ ERRORS[fault_message] || [:base, fault_message]
260
+ end
261
+
262
+ def params
263
+ @params ||= xml_querier.xpath('//payment:authoriseResponse/payment:paymentResult') do |result|
264
+ {
265
+ :psp_reference => result.text('./payment:pspReference'),
266
+ :result_code => result.text('./payment:resultCode'),
267
+ :auth_code => result.text('./payment:authCode'),
268
+ :refusal_reason => result.text('./payment:refusalReason')
269
+ }
270
+ end
271
+ end
272
+
273
+ private
274
+
275
+ def fault_message
276
+ @fault_message ||= xml_querier.text('//soap:Fault/faultstring')
277
+ end
278
+ end
279
+ end
280
+
281
+ class RecurringService < SimpleSOAPClient
282
+ ENDPOINT_URI = 'https://pal-%s.adyen.com/pal/servlet/soap/Recurring'
283
+
284
+ # TODO: rename to list_details and make shortcut method take the only necessary param
285
+ def list
286
+ call_webservice_action('listRecurringDetails', list_request_body, ListResponse)
287
+ end
288
+
289
+ def disable
290
+ call_webservice_action('disable', disable_request_body, DisableResponse)
291
+ end
292
+
293
+ private
294
+
295
+ def list_request_body
296
+ LIST_LAYOUT % [@params[:merchant_account], @params[:shopper][:reference]]
297
+ end
298
+
299
+ def disable_request_body
300
+ if reference = @params[:recurring_detail_reference]
301
+ reference = RECURRING_DETAIL_PARTIAL % reference
302
+ end
303
+ DISABLE_LAYOUT % [@params[:merchant_account], @params[:shopper][:reference], reference || '']
304
+ end
305
+
306
+ class DisableResponse < Response
307
+ response_attrs :response
308
+
309
+ def params
310
+ @params ||= { :response => xml_querier.text('//recurring:disableResponse/recurring:result/recurring:response') }
311
+ end
312
+ end
313
+
314
+ class ListResponse < Response
315
+ response_attrs :details, :last_known_shopper_email, :shopper_reference, :creation_date
316
+
317
+ def params
318
+ @params ||= xml_querier.xpath('//recurring:listRecurringDetailsResponse/recurring:result') do |result|
319
+ {
320
+ :creation_date => DateTime.parse(result.text('./recurring:creationDate')),
321
+ :details => result.xpath('.//recurring:RecurringDetail').map { |node| parse_recurring_detail(node) },
322
+ :last_known_shopper_email => result.text('./recurring:lastKnownShopperEmail'),
323
+ :shopper_reference => result.text('./recurring:shopperReference')
324
+ }
325
+ end
326
+ end
327
+
328
+ private
329
+
330
+ # @todo add support for elv
331
+ def parse_recurring_detail(node)
332
+ result = {
333
+ :recurring_detail_reference => node.text('./recurring:recurringDetailReference'),
334
+ :variant => node.text('./recurring:variant'),
335
+ :creation_date => DateTime.parse(node.text('./recurring:creationDate'))
336
+ }
337
+
338
+ card = node.xpath('./recurring:card')
339
+ if card.children.empty?
340
+ result[:bank] = parse_bank_details(node.xpath('./recurring:bank'))
341
+ else
342
+ result[:card] = parse_card_details(card)
343
+ end
344
+
345
+ result
346
+ end
347
+
348
+ def parse_card_details(card)
349
+ {
350
+ :expiry_date => Date.new(card.text('./payment:expiryYear').to_i, card.text('./payment:expiryMonth').to_i, -1),
351
+ :holder_name => card.text('./payment:holderName'),
352
+ :number => card.text('./payment:number')
353
+ }
354
+ end
355
+
356
+ def parse_bank_details(bank)
357
+ {
358
+ :bank_account_number => bank.text('./payment:bankAccountNumber'),
359
+ :bank_location_id => bank.text('./payment:bankLocationId'),
360
+ :bank_name => bank.text('./payment:bankName'),
361
+ :bic => bank.text('./payment:bic'),
362
+ :country_code => bank.text('./payment:countryCode'),
363
+ :iban => bank.text('./payment:iban'),
364
+ :owner_name => bank.text('./payment:ownerName')
365
+ }
366
+ end
367
+ end
368
+ end
278
369
  end
279
370
  end
280
371
 
@@ -291,49 +382,52 @@ module Adyen
291
382
  <?xml version="1.0"?>
292
383
  <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">
293
384
  <soap:Body>
294
- <ns1:authorise xmlns:ns1="http://payment.services.adyen.com">
295
- <ns1:paymentRequest>
296
- <merchantAccount xmlns="http://payment.services.adyen.com">%s</merchantAccount>
297
- <reference xmlns="http://payment.services.adyen.com">%s</reference>
385
+ <payment:authorise xmlns:payment="http://payment.services.adyen.com" xmlns:recurring="http://recurring.services.adyen.com" xmlns:common="http://common.services.adyen.com">
386
+ <payment:paymentRequest>
387
+ <payment:merchantAccount>%s</payment:merchantAccount>
388
+ <payment:reference>%s</payment:reference>
298
389
  %s
299
- </ns1:paymentRequest>
300
- </ns1:authorise>
390
+ </payment:paymentRequest>
391
+ </payment:authorise>
301
392
  </soap:Body>
302
393
  </soap:Envelope>
303
394
  EOS
304
395
 
305
396
  AMOUNT_PARTIAL = <<EOS
306
- <amount xmlns="http://payment.services.adyen.com">
307
- <currency xmlns="http://common.services.adyen.com">%s</currency>
308
- <value xmlns="http://common.services.adyen.com">%s</value>
309
- </amount>
397
+ <payment:amount>
398
+ <common:currency>%s</common:currency>
399
+ <common:value>%s</common:value>
400
+ </payment:amount>
310
401
  EOS
311
402
 
312
403
  CARD_PARTIAL = <<EOS
313
- <card xmlns="http://payment.services.adyen.com">
314
- <holderName>%s</holderName>
315
- <number>%s</number>
316
- <cvc>%s</cvc>
317
- <expiryYear>%s</expiryYear>
318
- <expiryMonth>%02d</expiryMonth>
319
- </card>
404
+ <payment:card>
405
+ <payment:holderName>%s</payment:holderName>
406
+ <payment:number>%s</payment:number>
407
+ <payment:cvc>%s</payment:cvc>
408
+ <payment:expiryYear>%s</payment:expiryYear>
409
+ <payment:expiryMonth>%02d</payment:expiryMonth>
410
+ </payment:card>
320
411
  EOS
321
412
 
322
413
  RECURRING_PARTIAL = <<EOS
323
- <recurring xmlns="http://recurring.services.adyen.com">
324
- <contract xmlns="http://payment.services.adyen.com">RECURRING</contract>
325
- </recurring>
414
+ <payment:recurring>
415
+ <payment:contract>RECURRING</payment:contract>
416
+ </payment:recurring>
326
417
  EOS
327
418
 
328
- RECURRING_PAYMENT_BODY_PARTIAL = RECURRING_PARTIAL + <<EOS
329
- <ns1:selectedRecurringDetailReference>%s</ns1:selectedRecurringDetailReference>
330
- <ns1:shopperInteraction>ContAuth</ns1:shopperInteraction>
419
+ RECURRING_PAYMENT_BODY_PARTIAL = <<EOS
420
+ <payment:recurring>
421
+ <payment:contract>RECURRING</payment:contract>
422
+ </payment:recurring>
423
+ <payment:selectedRecurringDetailReference>%s</payment:selectedRecurringDetailReference>
424
+ <payment:shopperInteraction>ContAuth</payment:shopperInteraction>
331
425
  EOS
332
426
 
333
427
  SHOPPER_PARTIALS = {
334
- :reference => ' <shopperReference xmlns="http://payment.services.adyen.com">%s</shopperReference>',
335
- :email => ' <shopperEmail xmlns="http://payment.services.adyen.com">%s</shopperEmail>',
336
- :ip => ' <shopperIP xmlns="http://payment.services.adyen.com">%s</shopperIP>',
428
+ :reference => ' <payment:shopperReference>%s</payment:shopperReference>',
429
+ :email => ' <payment:shopperEmail>%s</payment:shopperEmail>',
430
+ :ip => ' <payment:shopperIP>%s</payment:shopperIP>',
337
431
  }
338
432
  end
339
433
 
@@ -342,15 +436,15 @@ EOS
342
436
  <?xml version="1.0"?>
343
437
  <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">
344
438
  <soap:Body>
345
- <ns1:listRecurringDetails xmlns:ns1="http://recurring.services.adyen.com">
346
- <ns1:request>
347
- <ns1:recurring>
348
- <ns1:contract>RECURRING</ns1:contract>
349
- </ns1:recurring>
350
- <ns1:merchantAccount>%s</ns1:merchantAccount>
351
- <ns1:shopperReference>%s</ns1:shopperReference>
352
- </ns1:request>
353
- </ns1:listRecurringDetails>
439
+ <recurring:listRecurringDetails xmlns:recurring="http://recurring.services.adyen.com">
440
+ <recurring:request>
441
+ <recurring:recurring>
442
+ <recurring:contract>RECURRING</recurring:contract>
443
+ </recurring:recurring>
444
+ <recurring:merchantAccount>%s</recurring:merchantAccount>
445
+ <recurring:shopperReference>%s</recurring:shopperReference>
446
+ </recurring:request>
447
+ </recurring:listRecurringDetails>
354
448
  </soap:Body>
355
449
  </soap:Envelope>
356
450
  EOS
@@ -359,19 +453,19 @@ EOS
359
453
  <?xml version="1.0"?>
360
454
  <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">
361
455
  <soap:Body>
362
- <ns1:disable xmlns:ns1="http://recurring.services.adyen.com">
363
- <ns1:request>
364
- <ns1:merchantAccount>%s</ns1:merchantAccount>
365
- <ns1:shopperReference>%s</ns1:shopperReference>
456
+ <recurring:disable xmlns:recurring="http://recurring.services.adyen.com">
457
+ <recurring:request>
458
+ <recurring:merchantAccount>%s</recurring:merchantAccount>
459
+ <recurring:shopperReference>%s</recurring:shopperReference>
366
460
  %s
367
- </ns1:request>
368
- </ns1:disable>
461
+ </recurring:request>
462
+ </recurring:disable>
369
463
  </soap:Body>
370
464
  </soap:Envelope>
371
465
  EOS
372
466
 
373
467
  RECURRING_DETAIL_PARTIAL = <<EOS
374
- <ns1:recurringDetailReference>%s</ns1:recurringDetailReference>
468
+ <recurring:recurringDetailReference>%s</recurring:recurringDetailReference>
375
469
  EOS
376
470
  end
377
471
  end
data/lib/adyen.rb CHANGED
@@ -13,7 +13,7 @@ module Adyen
13
13
  # Version constant for the Adyen plugin.
14
14
  # DO NOT CHANGE THIS VALUE BY HAND. It will be updated automatically by
15
15
  # the gem:release rake task.
16
- VERSION = "0.3.8.20100924"
16
+ VERSION = "0.3.8.20100929"
17
17
 
18
18
  # Loads configuration settings from a Hash.
19
19
  #
data/spec/api_spec.rb CHANGED
@@ -105,6 +105,14 @@ module APISpecHelper
105
105
  end
106
106
  end
107
107
  end
108
+
109
+ def it_should_have_shortcut_methods_for_params_on_the_response
110
+ it "provides shortcut methods, on the response object, for all entries in the #params hash" do
111
+ @response.params.each do |key, value|
112
+ @response.send(key).should == value
113
+ end
114
+ end
115
+ end
108
116
  end
109
117
 
110
118
  class SOAPClient < Adyen::API::SimpleSOAPClient
@@ -160,6 +168,39 @@ describe Adyen::API do
160
168
  Adyen::API.password = 'secret'
161
169
  end
162
170
 
171
+ describe Adyen::API::Response do
172
+ before do
173
+ http_response = Net::HTTPOK.new('1.1', '200', 'OK')
174
+ http_response.add_field('Content-type', 'text/xml')
175
+ http_response.stub!(:body).and_return(AUTHORISE_RESPONSE)
176
+ @response = Adyen::API::Response.new(http_response)
177
+ end
178
+
179
+ it "returns a XMLQuerier instance with the response body" do
180
+ @response.xml_querier.should be_instance_of(Adyen::API::XMLQuerier)
181
+ @response.xml_querier.to_s.should == AUTHORISE_RESPONSE
182
+ end
183
+
184
+ describe "with a successful HTTP response" do
185
+ it "returns that the (HTTP) request was a success" do
186
+ @response.should_not be_a_http_failure
187
+ @response.should be_a_success
188
+ end
189
+ end
190
+
191
+ describe "with a failed HTTP response" do
192
+ before do
193
+ http_response = Net::HTTPBadRequest.new('1.1', '400', 'Bad request')
194
+ @response = Adyen::API::Response.new(http_response)
195
+ end
196
+
197
+ it "returns that the (HTTP) request was not a success" do
198
+ @response.should be_a_http_failure
199
+ @response.should_not be_a_success
200
+ end
201
+ end
202
+ end
203
+
163
204
  describe Adyen::API::SimpleSOAPClient do
164
205
  before do
165
206
  @client = APISpecHelper::SOAPClient.new(:reference => 'order-id')
@@ -183,7 +224,7 @@ describe Adyen::API do
183
224
  describe "call_webservice_action" do
184
225
  before do
185
226
  stub_net_http(AUTHORISE_RESPONSE)
186
- @client.call_webservice_action('Action', '<bananas>Yes, please</bananas>')
227
+ @response = @client.call_webservice_action('Action', '<bananas>Yes, please</bananas>', Adyen::API::Response)
187
228
  @request, @post = Net::HTTP.posted
188
229
  end
189
230
 
@@ -221,6 +262,11 @@ describe Adyen::API do
221
262
  'soapaction' => ['Action']
222
263
  }
223
264
  end
265
+
266
+ it "returns an Adyen::API::Response instance" do
267
+ @response.should be_instance_of(Adyen::API::Response)
268
+ @response.xml_querier.to_s.should == AUTHORISE_RESPONSE
269
+ end
224
270
  end
225
271
  end
226
272
 
@@ -300,16 +346,16 @@ describe Adyen::API do
300
346
  end
301
347
 
302
348
  it "includes the necessary recurring contract info if the `:recurring' param is truthful" do
303
- xpath('./recurring:recurring/payment:contract').should be_empty
349
+ xpath('./payment:recurring/payment:contract').should be_empty
304
350
  @payment.params[:recurring] = true
305
- text('./recurring:recurring/payment:contract').should == 'RECURRING'
351
+ text('./payment:recurring/payment:contract').should == 'RECURRING'
306
352
  end
307
353
  end
308
354
 
309
355
  describe "authorise_payment" do
310
356
  before do
311
357
  stub_net_http(AUTHORISE_RESPONSE)
312
- @payment.authorise_payment
358
+ @response = @payment.authorise_payment
313
359
  @request, @post = Net::HTTP.posted
314
360
  end
315
361
 
@@ -327,7 +373,7 @@ describe Adyen::API do
327
373
 
328
374
  for_each_xml_backend do
329
375
  it "returns a hash with parsed response details" do
330
- @payment.authorise_payment.should == {
376
+ @payment.authorise_payment.params.should == {
331
377
  :psp_reference => '9876543210987654',
332
378
  :result_code => 'Authorised',
333
379
  :auth_code => '1234',
@@ -335,6 +381,80 @@ describe Adyen::API do
335
381
  }
336
382
  end
337
383
  end
384
+
385
+ it_should_have_shortcut_methods_for_params_on_the_response
386
+
387
+ describe "with a authorized response" do
388
+ it "returns that the request was authorised" do
389
+ @response.should be_success
390
+ @response.should be_authorized
391
+ end
392
+ end
393
+
394
+ describe "with a `declined' response" do
395
+ before do
396
+ stub_net_http(AUTHORISATION_DECLINED_RESPONSE)
397
+ @response = @payment.authorise_payment
398
+ end
399
+
400
+ it "returns that the request was not authorised" do
401
+ @response.should_not be_success
402
+ @response.should_not be_authorized
403
+ end
404
+ end
405
+
406
+ describe "with a `invalid' response" do
407
+ before do
408
+ stub_net_http(AUTHORISE_REQUEST_INVALID_RESPONSE % 'validation 101 Invalid card number')
409
+ @response = @payment.authorise_payment
410
+ end
411
+
412
+ it "returns that the request was not authorised" do
413
+ @response.should_not be_success
414
+ @response.should_not be_authorized
415
+ end
416
+
417
+ it "it returns that the request was invalid" do
418
+ @response.should be_invalid_request
419
+ end
420
+
421
+ it "returns creditcard validation errors" do
422
+ [
423
+ ["validation 101 Invalid card number", [:number, 'is not a valid creditcard number']],
424
+ ["validation 103 CVC is not the right length", [:cvc, 'is not the right length']],
425
+ ["validation 128 Card Holder Missing", [:holder_name, 'can’t be blank']],
426
+ ["validation Couldn't parse expiry year", [:expiry_year, 'could not be recognized']],
427
+ ["validation Expiry month should be between 1 and 12 inclusive", [:expiry_month, 'could not be recognized']],
428
+ ].each do |message, error|
429
+ response_with_fault_message(message).error.should == error
430
+ end
431
+ end
432
+
433
+ it "returns any other fault messages on `base'" do
434
+ message = "validation 130 Reference Missing"
435
+ response_with_fault_message(message).error.should == [:base, message]
436
+ end
437
+
438
+ it "returns the original message corresponding to the given attribute and message" do
439
+ [
440
+ ["validation 101 Invalid card number", [:number, 'is not a valid creditcard number']],
441
+ ["validation 103 CVC is not the right length", [:cvc, 'is not the right length']],
442
+ ["validation 128 Card Holder Missing", [:holder_name, 'can’t be blank']],
443
+ ["validation Couldn't parse expiry year", [:expiry_year, 'could not be recognized']],
444
+ ["validation Expiry month should be between 1 and 12 inclusive", [:expiry_month, 'could not be recognized']],
445
+ ["validation 130 Reference Missing", [:base, 'validation 130 Reference Missing']],
446
+ ].each do |expected, attr_and_message|
447
+ Adyen::API::PaymentService::AuthorizationResponse.original_fault_message_for(*attr_and_message).should == expected
448
+ end
449
+ end
450
+
451
+ private
452
+
453
+ def response_with_fault_message(message)
454
+ stub_net_http(AUTHORISE_REQUEST_INVALID_RESPONSE % message)
455
+ @response = @payment.authorise_payment
456
+ end
457
+ end
338
458
  end
339
459
 
340
460
  describe "authorise_recurring_payment_request_body" do
@@ -349,7 +469,7 @@ describe Adyen::API do
349
469
  end
350
470
 
351
471
  it "includes the contract type, which is always `RECURRING'" do
352
- text('./recurring:recurring/payment:contract').should == 'RECURRING'
472
+ text('./payment:recurring/payment:contract').should == 'RECURRING'
353
473
  end
354
474
 
355
475
  it "obviously includes the obligatory self-‘describing’ nonsense parameters" do
@@ -369,7 +489,7 @@ describe Adyen::API do
369
489
  describe "authorise_recurring_payment" do
370
490
  before do
371
491
  stub_net_http(AUTHORISE_RESPONSE)
372
- @payment.authorise_recurring_payment
492
+ @response = @payment.authorise_recurring_payment
373
493
  @request, @post = Net::HTTP.posted
374
494
  end
375
495
 
@@ -387,7 +507,7 @@ describe Adyen::API do
387
507
 
388
508
  for_each_xml_backend do
389
509
  it "returns a hash with parsed response details" do
390
- @payment.authorise_recurring_payment.should == {
510
+ @payment.authorise_recurring_payment.params.should == {
391
511
  :psp_reference => '9876543210987654',
392
512
  :result_code => 'Authorised',
393
513
  :auth_code => '1234',
@@ -395,6 +515,8 @@ describe Adyen::API do
395
515
  }
396
516
  end
397
517
  end
518
+
519
+ it_should_have_shortcut_methods_for_params_on_the_response
398
520
  end
399
521
  end
400
522
 
@@ -438,7 +560,7 @@ describe Adyen::API do
438
560
  describe "list" do
439
561
  before do
440
562
  stub_net_http(LIST_RESPONSE)
441
- @recurring.list
563
+ @response = @recurring.list
442
564
  @request, @post = Net::HTTP.posted
443
565
  end
444
566
 
@@ -456,7 +578,7 @@ describe Adyen::API do
456
578
 
457
579
  for_each_xml_backend do
458
580
  it "returns a hash with parsed response details" do
459
- @recurring.list.should == {
581
+ @recurring.list.params.should == {
460
582
  :creation_date => DateTime.parse('2009-10-27T11:26:22.203+01:00'),
461
583
  :last_known_shopper_email => 's.hopper@example.com',
462
584
  :shopper_reference => 'user-id',
@@ -488,6 +610,8 @@ describe Adyen::API do
488
610
  ],
489
611
  }
490
612
  end
613
+
614
+ it_should_have_shortcut_methods_for_params_on_the_response
491
615
  end
492
616
 
493
617
  describe "disable_request_body" do
@@ -519,7 +643,7 @@ describe Adyen::API do
519
643
  describe "disable" do
520
644
  before do
521
645
  stub_net_http(DISABLE_RESPONSE)
522
- @recurring.disable
646
+ @response = @recurring.disable
523
647
  @request, @post = Net::HTTP.posted
524
648
  end
525
649
 
@@ -537,9 +661,11 @@ describe Adyen::API do
537
661
 
538
662
  for_each_xml_backend do
539
663
  it "returns a hash with parsed response details" do
540
- @recurring.disable.should == { :response => '[detail-successfully-disabled]' }
664
+ @recurring.disable.params.should == { :response => '[detail-successfully-disabled]' }
541
665
  end
542
666
  end
667
+
668
+ it_should_have_shortcut_methods_for_params_on_the_response
543
669
  end
544
670
  end
545
671
  end
@@ -568,6 +694,40 @@ AUTHORISE_RESPONSE = <<EOS
568
694
  </soap:Envelope>
569
695
  EOS
570
696
 
697
+ AUTHORISATION_DECLINED_RESPONSE = <<EOS
698
+ <?xml version="1.0" encoding="UTF-8"?>
699
+ <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">
700
+ <soap:Body>
701
+ <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
702
+ <ns1:paymentResult>
703
+ <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
704
+ <authCode xmlns="http://payment.services.adyen.com">1234</authCode>
705
+ <dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
706
+ <dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
707
+ <fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
708
+ <issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
709
+ <md xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
710
+ <paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
711
+ <pspReference xmlns="http://payment.services.adyen.com">9876543210987654</pspReference>
712
+ <refusalReason xmlns="http://payment.services.adyen.com">You need to actually own money.</refusalReason>
713
+ <resultCode xmlns="http://payment.services.adyen.com">Refused</resultCode>
714
+ </ns1:paymentResult>
715
+ </ns1:authoriseResponse>
716
+ </soap:Body>
717
+ </soap:Envelope>
718
+ EOS
719
+
720
+ AUTHORISE_REQUEST_INVALID_RESPONSE = <<EOS
721
+ <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">
722
+ <soap:Body>
723
+ <soap:Fault>
724
+ <faultcode>soap:Server</faultcode>
725
+ <faultstring>%s</faultstring>
726
+ </soap:Fault>
727
+ </soap:Body>
728
+ </soap:Envelope>
729
+ EOS
730
+
571
731
  LIST_RESPONSE = <<EOS
572
732
  <?xml version="1.0"?>
573
733
  <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">
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fingertips-adyen
3
3
  version: !ruby/object:Gem::Version
4
- hash: 40201743
4
+ hash: 40201973
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
9
  - 8
10
- - 20100924
11
- version: 0.3.8.20100924
10
+ - 20100929
11
+ version: 0.3.8.20100929
12
12
  platform: ruby
13
13
  authors:
14
14
  - Willem van Bergen
@@ -19,7 +19,7 @@ autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2010-09-23 00:00:00 +02:00
22
+ date: 2010-09-29 00:00:00 +02:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency