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.
- data/TODO +4 -0
- data/adyen.gemspec +2 -2
- data/lib/adyen/api.rb +256 -162
- data/lib/adyen.rb +1 -1
- data/spec/api_spec.rb +172 -12
- metadata +4 -4
data/TODO
CHANGED
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.
|
4
|
-
s.date = "2010-09-
|
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
|
-
|
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
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
-
|
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
|
159
|
-
|
84
|
+
def initialize(http_response)
|
85
|
+
@http_response = http_response
|
160
86
|
end
|
161
87
|
|
162
|
-
|
163
|
-
|
164
|
-
|
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
|
-
# @
|
170
|
-
def
|
171
|
-
|
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
|
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
|
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
|
-
<
|
295
|
-
<
|
296
|
-
<merchantAccount
|
297
|
-
<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
|
-
</
|
300
|
-
</
|
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
|
307
|
-
<currency
|
308
|
-
<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
|
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
|
324
|
-
<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 =
|
329
|
-
<
|
330
|
-
|
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
|
335
|
-
:email => ' <shopperEmail
|
336
|
-
:ip => ' <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
|
-
<
|
346
|
-
<
|
347
|
-
<
|
348
|
-
<
|
349
|
-
</
|
350
|
-
<
|
351
|
-
<
|
352
|
-
</
|
353
|
-
</
|
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
|
-
<
|
363
|
-
<
|
364
|
-
<
|
365
|
-
<
|
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
|
-
</
|
368
|
-
</
|
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
|
-
<
|
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.
|
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('./
|
349
|
+
xpath('./payment:recurring/payment:contract').should be_empty
|
304
350
|
@payment.params[:recurring] = true
|
305
|
-
text('./
|
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('./
|
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:
|
4
|
+
hash: 40201973
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
9
|
- 8
|
10
|
-
-
|
11
|
-
version: 0.3.8.
|
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-
|
22
|
+
date: 2010-09-29 00:00:00 +02:00
|
23
23
|
default_executable:
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|