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.
- 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
|