fingertips-adyen 0.3.8.20100924 → 0.3.8.20100929

Sign up to get free protection for your applications and to get access to all the features.
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