adyen_jpiqueras 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +30 -0
- data/CHANGELOG.md +128 -0
- data/CONTRIBUTING.md +85 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/Rakefile +54 -0
- data/adyen_jpiqueras.gemspec +44 -0
- data/config.ru +5 -0
- data/lib/adyen.rb +16 -0
- data/lib/adyen/api.rb +424 -0
- data/lib/adyen/api/cacert.pem +3894 -0
- data/lib/adyen/api/payment_service.rb +374 -0
- data/lib/adyen/api/recurring_service.rb +188 -0
- data/lib/adyen/api/response.rb +61 -0
- data/lib/adyen/api/simple_soap_client.rb +134 -0
- data/lib/adyen/api/templates/payment_service.rb +159 -0
- data/lib/adyen/api/templates/recurring_service.rb +71 -0
- data/lib/adyen/api/test_helpers.rb +133 -0
- data/lib/adyen/api/xml_querier.rb +137 -0
- data/lib/adyen/base.rb +17 -0
- data/lib/adyen/configuration.rb +179 -0
- data/lib/adyen/form.rb +419 -0
- data/lib/adyen/hpp.rb +27 -0
- data/lib/adyen/hpp/request.rb +192 -0
- data/lib/adyen/hpp/response.rb +52 -0
- data/lib/adyen/hpp/signature.rb +34 -0
- data/lib/adyen/matchers.rb +92 -0
- data/lib/adyen/notification_generator.rb +30 -0
- data/lib/adyen/railtie.rb +13 -0
- data/lib/adyen/rest.rb +67 -0
- data/lib/adyen/rest/authorise_payment.rb +234 -0
- data/lib/adyen/rest/authorise_recurring_payment.rb +46 -0
- data/lib/adyen/rest/client.rb +127 -0
- data/lib/adyen/rest/errors.rb +33 -0
- data/lib/adyen/rest/modify_payment.rb +89 -0
- data/lib/adyen/rest/payout.rb +89 -0
- data/lib/adyen/rest/request.rb +104 -0
- data/lib/adyen/rest/response.rb +80 -0
- data/lib/adyen/rest/signature.rb +27 -0
- data/lib/adyen/signature.rb +76 -0
- data/lib/adyen/templates/notification_migration.rb +29 -0
- data/lib/adyen/templates/notification_model.rb +69 -0
- data/lib/adyen/util.rb +147 -0
- data/lib/adyen/version.rb +5 -0
- data/spec/api/api_spec.rb +231 -0
- data/spec/api/payment_service_spec.rb +505 -0
- data/spec/api/recurring_service_spec.rb +236 -0
- data/spec/api/response_spec.rb +59 -0
- data/spec/api/simple_soap_client_spec.rb +133 -0
- data/spec/api/spec_helper.rb +463 -0
- data/spec/api/test_helpers_spec.rb +84 -0
- data/spec/functional/api_spec.rb +117 -0
- data/spec/functional/initializer.rb.ci +3 -0
- data/spec/functional/initializer.rb.sample +3 -0
- data/spec/spec_helper.rb +8 -0
- data/test/form_test.rb +303 -0
- data/test/functional/payment_authorisation_api_test.rb +107 -0
- data/test/functional/payment_modification_api_test.rb +58 -0
- data/test/functional/payout_api_test.rb +93 -0
- data/test/helpers/capybara.rb +12 -0
- data/test/helpers/configure_adyen.rb +6 -0
- data/test/helpers/example_server.rb +136 -0
- data/test/helpers/public/adyen.encrypt.js +679 -0
- data/test/helpers/public/adyen.encrypt.min.js +14 -0
- data/test/helpers/test_cards.rb +20 -0
- data/test/helpers/views/authorized.erb +7 -0
- data/test/helpers/views/hpp.erb +20 -0
- data/test/helpers/views/index.erb +6 -0
- data/test/helpers/views/pay.erb +36 -0
- data/test/helpers/views/redirect_shopper.erb +18 -0
- data/test/hpp/signature_test.rb +37 -0
- data/test/hpp_test.rb +250 -0
- data/test/integration/hpp_integration_test.rb +52 -0
- data/test/integration/payment_using_3d_secure_integration_test.rb +41 -0
- data/test/integration/payment_with_client_side_encryption_integration_test.rb +26 -0
- data/test/rest/signature_test.rb +36 -0
- data/test/rest_list_recurring_details_response_test.rb +22 -0
- data/test/rest_request_test.rb +43 -0
- data/test/rest_response_test.rb +19 -0
- data/test/signature_test.rb +76 -0
- data/test/test_helper.rb +45 -0
- data/test/util_test.rb +78 -0
- data/yard_extensions.rb +16 -0
- metadata +308 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
# @private
|
2
|
+
class CreateAdyenNotifications < ActiveRecord::Migration
|
3
|
+
|
4
|
+
def self.up
|
5
|
+
create_table :adyen_notifications do |t|
|
6
|
+
t.boolean :live, :null => false, :default => false
|
7
|
+
t.string :event_code, :null => false, :limit => 40
|
8
|
+
t.string :psp_reference, :null => false, :limit => 50
|
9
|
+
t.string :original_reference, :null => true
|
10
|
+
t.string :merchant_reference, :null => false
|
11
|
+
t.string :merchant_account_code, :null => false
|
12
|
+
t.datetime :event_date, :null => false
|
13
|
+
t.boolean :success, :null => false, :default => false
|
14
|
+
t.string :payment_method, :null => true
|
15
|
+
t.string :operations, :null => true
|
16
|
+
t.text :reason, :null => true
|
17
|
+
t.string :currency, :null => true, :limit => 3
|
18
|
+
t.integer :value, :null => true
|
19
|
+
t.boolean :processed, :null => false, :default => false
|
20
|
+
t.timestamps
|
21
|
+
end
|
22
|
+
|
23
|
+
add_index :adyen_notifications, [:merchant_account_code, :psp_reference, :event_code, :success], :unique => true, :name => 'adyen_notification_uniqueness'
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.down
|
27
|
+
drop_table :adyen_notifications
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# The +AdyenNotification+ class handles notifications sent by Adyen to your servers.
|
2
|
+
#
|
3
|
+
# Because notifications contain important payment status information, you should store
|
4
|
+
# these notifications in your database. For this reason, +AdyenNotification+ inherits
|
5
|
+
# from +ActiveRecord::Base+, and a migration is included to simply create a suitable table
|
6
|
+
# to store the notifications in.
|
7
|
+
#
|
8
|
+
# Adyen can either send notifications to you via HTTP POST requests, or SOAP requests.
|
9
|
+
# Because SOAP is not really well supported in Rails and setting up a SOAP server is
|
10
|
+
# not trivial, only handling HTTP POST notifications is currently supported.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# @notification = AdyenNotification.log(request)
|
14
|
+
# if @notification.successful_authorisation?
|
15
|
+
# @invoice = Invoice.find(@notification.merchant_reference)
|
16
|
+
# @invoice.set_paid!
|
17
|
+
# end
|
18
|
+
class AdyenNotification < ActiveRecord::Base
|
19
|
+
# A notification should always include an event_code
|
20
|
+
validates_presence_of :event_code
|
21
|
+
|
22
|
+
# A notification should always include a psp_reference
|
23
|
+
validates_presence_of :psp_reference
|
24
|
+
|
25
|
+
# A notification should be unique using the composed key of
|
26
|
+
# [:merchant_account_code, :psp_reference, :event_code, :success]
|
27
|
+
validates_uniqueness_of :success, :scope => [:merchant_account_code, :psp_reference, :event_code]
|
28
|
+
|
29
|
+
# Make sure we don't end up with an original_reference with an empty string
|
30
|
+
before_validation { |notification| notification.original_reference = nil if notification.original_reference.blank? }
|
31
|
+
|
32
|
+
# Logs an incoming notification into the database.
|
33
|
+
#
|
34
|
+
# @param [Hash] params The notification parameters that should be stored in the database.
|
35
|
+
# @return [Adyen::Notification] The initiated and persisted notification instance.
|
36
|
+
# @raise This method will raise an exception if the notification cannot be stored.
|
37
|
+
# @see Adyen::Notification::HttpPost.log
|
38
|
+
def self.log(params)
|
39
|
+
# Assign explicit each attribute from CamelCase notation to notification
|
40
|
+
# For example, merchantReference will be converted to merchant_reference
|
41
|
+
self.new.tap do |notification|
|
42
|
+
params.each do |key, value|
|
43
|
+
setter = "#{key.to_s.underscore}="
|
44
|
+
notification.send(setter, value) if notification.respond_to?(setter)
|
45
|
+
end
|
46
|
+
|
47
|
+
notification.save!
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns true if this notification is an AUTHORISATION notification
|
52
|
+
# @return [true, false] true iff event_code == 'AUTHORISATION'
|
53
|
+
# @see Adyen.notification#successful_authorisation?
|
54
|
+
def authorisation?
|
55
|
+
event_code == 'AUTHORISATION'
|
56
|
+
end
|
57
|
+
|
58
|
+
alias_method :authorization?, :authorisation?
|
59
|
+
|
60
|
+
# Returns true if this notification is an AUTHORISATION notification and
|
61
|
+
# the success status indicates that the authorization was successfull.
|
62
|
+
# @return [true, false] true iff the notification is an authorization
|
63
|
+
# and the authorization was successful according to the success field.
|
64
|
+
def successful_authorisation?
|
65
|
+
authorisation? && success?
|
66
|
+
end
|
67
|
+
|
68
|
+
alias_method :successful_authorization?, :successful_authorisation?
|
69
|
+
end
|
data/lib/adyen/util.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'openssl'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module Adyen
|
6
|
+
module Util
|
7
|
+
extend self
|
8
|
+
|
9
|
+
# Returns a valid Adyen string representation for a date
|
10
|
+
def format_date(date)
|
11
|
+
case date
|
12
|
+
when Date, DateTime, Time
|
13
|
+
date.strftime('%Y-%m-%d')
|
14
|
+
when String
|
15
|
+
raise ArgumentError, "Invalid date notation: #{date.inspect}!" unless /^\d{4}-\d{2}-\d{2}$/ =~ date
|
16
|
+
date
|
17
|
+
else
|
18
|
+
raise ArgumentError, "Cannot convert #{date.inspect} to date!"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns a valid Adyen string representation for a timestamp
|
23
|
+
def format_timestamp(time)
|
24
|
+
case time
|
25
|
+
when Date, DateTime, Time
|
26
|
+
time.strftime('%Y-%m-%dT%H:%M:%SZ')
|
27
|
+
when String
|
28
|
+
raise ArgumentError, "Invalid timestamp notation: #{time.inspect}!" unless /^\d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}Z$/ =~ time
|
29
|
+
time
|
30
|
+
else
|
31
|
+
raise ArgumentError, "Cannot convert #{time.inspect} to timestamp!"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a base64-encoded signature for a message
|
36
|
+
# @param [String] hmac_key The secret key to use for the HMAC signature.
|
37
|
+
# @param [String] message The message to sign.
|
38
|
+
# @return [String] The signature, base64-encoded.
|
39
|
+
def hmac_base64(hmac_key, message)
|
40
|
+
digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), hmac_key, message)
|
41
|
+
Base64.strict_encode64(digest).strip
|
42
|
+
end
|
43
|
+
|
44
|
+
# Retuns a message gzip-compressed and base64-encoded.
|
45
|
+
# @param [String] message The message to compress and encode.
|
46
|
+
# @return [String] The compressed and encoded version of the message
|
47
|
+
def gzip_base64(message)
|
48
|
+
sio = StringIO.new
|
49
|
+
gz = Zlib::GzipWriter.new(sio)
|
50
|
+
gz.write(message)
|
51
|
+
gz.close
|
52
|
+
Base64.strict_encode64(sio.string)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the camelized version of a string.
|
56
|
+
# @param [:to_s] identifier The identifier to turn to camelcase.
|
57
|
+
# @return [String] The camelcase version of the identifier provided.
|
58
|
+
def camelize(identifier)
|
59
|
+
CAMELCASE_EXCEPTIONS[identifier.to_s] || identifier.to_s.gsub(/_+(.)/) { $1.upcase }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the underscore version of a string.
|
63
|
+
# @param [:to_s] identifier The identifier to turn to underscore notation.
|
64
|
+
# @return [String] The underscore version of the identifier provided.
|
65
|
+
def underscore(identifier)
|
66
|
+
UNDERSCORE_EXCEPTIONS[identifier.to_s] || identifier.to_s
|
67
|
+
.gsub(/([A-Z]{2,})([A-Z])/) { "#{$1.downcase}#{$2}" }
|
68
|
+
.gsub(/(?!\A)([A-Z][a-z]*)/, '_\1')
|
69
|
+
.downcase
|
70
|
+
end
|
71
|
+
|
72
|
+
# Transforms the nested parameters Hash into a 'flat' Hash which is understood by adyen. This is:
|
73
|
+
# * all keys are camelized
|
74
|
+
# * all keys are stringified
|
75
|
+
# * nested hash is flattened, keys are prefixed with root key
|
76
|
+
#
|
77
|
+
# @example
|
78
|
+
# flatten {:billing_address => { :street => 'My Street'}}
|
79
|
+
#
|
80
|
+
# # resolves in:
|
81
|
+
# {'billingAddress.street' => 'My Street'}
|
82
|
+
#
|
83
|
+
# @param [Hash] nested_hash The nested hash to transform
|
84
|
+
# @param [String] prefix The prefix to add to the key
|
85
|
+
# @param [Hash] return_hash The new hash which is retruned (needed for recursive calls)
|
86
|
+
# @return [Hash] The return hash filled with camelized and prefixed key, stringified value
|
87
|
+
def flatten(nested_hash, prefix = "", return_hash = {})
|
88
|
+
nested_hash ||= {}
|
89
|
+
nested_hash.inject(return_hash) do |hash, (key, value)|
|
90
|
+
key = "#{prefix}#{camelize(key)}"
|
91
|
+
if value.is_a?(Hash)
|
92
|
+
flatten(value, "#{key}.", return_hash)
|
93
|
+
else
|
94
|
+
hash[key] = value.to_s
|
95
|
+
end
|
96
|
+
hash
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Transforms a flat hash into a nested hash structure.
|
101
|
+
# * all keys are underscored
|
102
|
+
# * all keys are stringified
|
103
|
+
# * flattened hash is deflattened, using . as namespace separator
|
104
|
+
#
|
105
|
+
# @example
|
106
|
+
# deflatten {'billingAddress.street' => 'My Street'}
|
107
|
+
#
|
108
|
+
# # resolves in:
|
109
|
+
# {'billing_address' => { 'street' => 'My Street'}}
|
110
|
+
#
|
111
|
+
# @param [Hash] flattened_hash The flat hash to transform
|
112
|
+
# @param [Hash] return_hash The new hash which will be returned (needed for recursive calls)
|
113
|
+
# @return [Hash] A nested hash structure, using strings as key.
|
114
|
+
def deflatten(flattened_hash, return_hash = {})
|
115
|
+
return return_hash if flattened_hash.nil?
|
116
|
+
flattened_hash.each do |key, value|
|
117
|
+
deflatten_pair(key, value, return_hash)
|
118
|
+
end
|
119
|
+
return_hash
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def deflatten_pair(key, value, return_hash)
|
125
|
+
head, rest = key.split('.', 2)
|
126
|
+
key = underscore(head)
|
127
|
+
if rest.nil?
|
128
|
+
raise ArgumentError, "Duplicate key in flattened hash." if return_hash.key?(key)
|
129
|
+
return_hash[key] = value
|
130
|
+
else
|
131
|
+
return_hash[key] ||= {}
|
132
|
+
raise ArgumentError, "Key nesting conflict in flattened hash." unless return_hash[key].is_a?(Hash)
|
133
|
+
deflatten_pair(rest, value, return_hash[key])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# This hash contains exceptions to the standard underscore to camelcase conversion rules.
|
138
|
+
CAMELCASE_EXCEPTIONS = {
|
139
|
+
'shopper_ip' => 'shopperIP'
|
140
|
+
}
|
141
|
+
|
142
|
+
# This hash contains exceptions to the standard camelcase to underscore conversion rules.
|
143
|
+
UNDERSCORE_EXCEPTIONS = CAMELCASE_EXCEPTIONS.invert
|
144
|
+
|
145
|
+
private_constant :CAMELCASE_EXCEPTIONS, :UNDERSCORE_EXCEPTIONS
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'api/spec_helper'
|
3
|
+
|
4
|
+
describe Adyen::API do
|
5
|
+
include APISpecHelper
|
6
|
+
|
7
|
+
describe "shortcut methods" do
|
8
|
+
describe "for the PaymentService" do
|
9
|
+
before do
|
10
|
+
@payment = double('PaymentService')
|
11
|
+
end
|
12
|
+
|
13
|
+
def should_map_shortcut_to(method, params)
|
14
|
+
Adyen::API::PaymentService.should_receive(:new).with(params).and_return(@payment)
|
15
|
+
@payment.should_receive(method)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "performs a `authorise payment' request without enabling :recurring" do
|
19
|
+
should_map_shortcut_to(:authorise_payment,
|
20
|
+
:reference => 'order-id',
|
21
|
+
:amount => { :currency => 'EUR', :value => 1234 },
|
22
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
23
|
+
:card => { :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' },
|
24
|
+
:recurring => false,
|
25
|
+
:fraud_offset => nil,
|
26
|
+
:instant_capture => false
|
27
|
+
)
|
28
|
+
Adyen::API.authorise_payment('order-id',
|
29
|
+
{ :currency => 'EUR', :value => 1234 },
|
30
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' },
|
31
|
+
{ :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' }
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "performs a `authorise payment' request with additional :fraud_offset" do
|
36
|
+
should_map_shortcut_to(:authorise_payment,
|
37
|
+
:reference => 'order-id',
|
38
|
+
:amount => { :currency => 'EUR', :value => 1234 },
|
39
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
40
|
+
:card => { :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' },
|
41
|
+
:recurring => false,
|
42
|
+
:fraud_offset => -100,
|
43
|
+
:instant_capture => false
|
44
|
+
)
|
45
|
+
Adyen::API.authorise_payment('order-id',
|
46
|
+
{ :currency => 'EUR', :value => 1234 },
|
47
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' },
|
48
|
+
{ :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' },
|
49
|
+
false,
|
50
|
+
-100,
|
51
|
+
false
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "performs a `authorise payment' request with enabling :recurring" do
|
56
|
+
should_map_shortcut_to(:authorise_payment,
|
57
|
+
:reference => 'order-id',
|
58
|
+
:amount => { :currency => 'EUR', :value => 1234 },
|
59
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
60
|
+
:card => { :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' },
|
61
|
+
:recurring => true,
|
62
|
+
:fraud_offset => nil,
|
63
|
+
:instant_capture => false,
|
64
|
+
)
|
65
|
+
Adyen::API.authorise_payment('order-id',
|
66
|
+
{ :currency => 'EUR', :value => 1234 },
|
67
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' },
|
68
|
+
{ :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737' },
|
69
|
+
true,
|
70
|
+
nil,
|
71
|
+
false
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "performs a `authorise recurring payment' request without specific detail" do
|
76
|
+
should_map_shortcut_to(:authorise_recurring_payment,
|
77
|
+
:reference => 'order-id',
|
78
|
+
:amount => { :currency => 'EUR', :value => 1234 },
|
79
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
80
|
+
:recurring_detail_reference => 'LATEST',
|
81
|
+
:instant_capture => false,
|
82
|
+
:fraud_offset => nil
|
83
|
+
)
|
84
|
+
Adyen::API.authorise_recurring_payment('order-id',
|
85
|
+
{ :currency => 'EUR', :value => 1234 },
|
86
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' }
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "performs a `authorise recurring payment' request with specific detail" do
|
91
|
+
should_map_shortcut_to(:authorise_recurring_payment,
|
92
|
+
:reference => 'order-id',
|
93
|
+
:amount => { :currency => 'EUR', :value => 1234 },
|
94
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
95
|
+
:recurring_detail_reference => 'recurring-detail-reference',
|
96
|
+
:instant_capture => false,
|
97
|
+
:fraud_offset => nil
|
98
|
+
)
|
99
|
+
Adyen::API.authorise_recurring_payment('order-id',
|
100
|
+
{ :currency => 'EUR', :value => 1234 },
|
101
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' },
|
102
|
+
'recurring-detail-reference'
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "performs a `authorise recurring payment' request with specific detail and fraud offset" do
|
107
|
+
should_map_shortcut_to(:authorise_recurring_payment,
|
108
|
+
:reference => 'order-id',
|
109
|
+
:amount => { :currency => 'EUR', :value => 1234 },
|
110
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
111
|
+
:recurring_detail_reference => 'recurring-detail-reference',
|
112
|
+
:fraud_offset => 50,
|
113
|
+
:instant_capture => false
|
114
|
+
)
|
115
|
+
Adyen::API.authorise_recurring_payment('order-id',
|
116
|
+
{ :currency => 'EUR', :value => 1234 },
|
117
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' },
|
118
|
+
'recurring-detail-reference',
|
119
|
+
50,
|
120
|
+
false
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "performs a `authorise one-click payment' request with specific detail" do
|
125
|
+
should_map_shortcut_to(:authorise_one_click_payment,
|
126
|
+
:reference => 'order-id',
|
127
|
+
:amount => { :currency => 'EUR', :value => 1234 },
|
128
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
129
|
+
:card => { :cvc => '737' },
|
130
|
+
:recurring_detail_reference => 'recurring-detail-reference',
|
131
|
+
:fraud_offset => nil,
|
132
|
+
:instant_capture => false
|
133
|
+
)
|
134
|
+
Adyen::API.authorise_one_click_payment('order-id',
|
135
|
+
{ :currency => 'EUR', :value => 1234 },
|
136
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' },
|
137
|
+
{ :cvc => '737' },
|
138
|
+
'recurring-detail-reference'
|
139
|
+
)
|
140
|
+
end
|
141
|
+
|
142
|
+
it "performs a `authorise one-click payment' request with specific detail and fraud offset" do
|
143
|
+
should_map_shortcut_to(:authorise_one_click_payment,
|
144
|
+
:reference => 'order-id',
|
145
|
+
:amount => { :currency => 'EUR', :value => 1234 },
|
146
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
147
|
+
:card => { :cvc => '737' },
|
148
|
+
:recurring_detail_reference => 'recurring-detail-reference',
|
149
|
+
:fraud_offset => -10,
|
150
|
+
:instant_capture => false,
|
151
|
+
)
|
152
|
+
Adyen::API.authorise_one_click_payment('order-id',
|
153
|
+
{ :currency => 'EUR', :value => 1234 },
|
154
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' },
|
155
|
+
{ :cvc => '737' },
|
156
|
+
'recurring-detail-reference',
|
157
|
+
-10,
|
158
|
+
false
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "performs a `capture' request" do
|
163
|
+
should_map_shortcut_to(:capture, :psp_reference => 'original-psp-reference', :amount => { :currency => 'EUR', :value => '1234' })
|
164
|
+
Adyen::API.capture_payment('original-psp-reference', { :currency => 'EUR', :value => '1234' })
|
165
|
+
end
|
166
|
+
|
167
|
+
it "performs a `refund payment' request" do
|
168
|
+
should_map_shortcut_to(:refund, :psp_reference => 'original-psp-reference', :amount => { :currency => 'EUR', :value => '1234' })
|
169
|
+
Adyen::API.refund_payment('original-psp-reference', { :currency => 'EUR', :value => '1234' })
|
170
|
+
end
|
171
|
+
|
172
|
+
it "performs a `cancel or refund payment' request" do
|
173
|
+
should_map_shortcut_to(:cancel_or_refund, :psp_reference => 'original-psp-reference')
|
174
|
+
Adyen::API.cancel_or_refund_payment('original-psp-reference')
|
175
|
+
end
|
176
|
+
|
177
|
+
it "performs a `cancel payment' request" do
|
178
|
+
should_map_shortcut_to(:cancel, :psp_reference => 'original-psp-reference')
|
179
|
+
Adyen::API.cancel_payment('original-psp-reference')
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "for the RecurringService" do
|
184
|
+
before do
|
185
|
+
@recurring = double('RecurringService')
|
186
|
+
end
|
187
|
+
|
188
|
+
def should_map_shortcut_to(method, params)
|
189
|
+
Adyen::API::RecurringService.should_receive(:new).with(params).and_return(@recurring)
|
190
|
+
@recurring.should_receive(method)
|
191
|
+
end
|
192
|
+
|
193
|
+
it "performs a `tokenize creditcard details' request" do
|
194
|
+
should_map_shortcut_to(:store_token,
|
195
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
196
|
+
:card => { :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111' }
|
197
|
+
)
|
198
|
+
Adyen::API.store_recurring_token(
|
199
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' },
|
200
|
+
{ :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon Hopper", :number => '4444333322221111' }
|
201
|
+
)
|
202
|
+
end
|
203
|
+
|
204
|
+
it "performs a `tokenize ELV details' request" do
|
205
|
+
should_map_shortcut_to(:store_token,
|
206
|
+
:shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
|
207
|
+
:elv => { :bank_location => "Berlin", :bank_name => "TestBank", :bank_location_id => "12345678", :holder_name => "Simon Hopper", :number => "1234567890" }
|
208
|
+
)
|
209
|
+
Adyen::API.store_recurring_token(
|
210
|
+
{ :reference => 'user-id', :email => 's.hopper@example.com' },
|
211
|
+
{ :bank_location => "Berlin", :bank_name => "TestBank", :bank_location_id => "12345678", :holder_name => "Simon Hopper", :number => "1234567890" }
|
212
|
+
)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "preforms a `list recurring details' request" do
|
216
|
+
should_map_shortcut_to(:list, :shopper => { :reference => 'user-id' })
|
217
|
+
Adyen::API.list_recurring_details('user-id')
|
218
|
+
end
|
219
|
+
|
220
|
+
it "performs a `disable recurring contract' request for all details" do
|
221
|
+
should_map_shortcut_to(:disable, :shopper => { :reference => 'user-id' }, :recurring_detail_reference => nil)
|
222
|
+
Adyen::API.disable_recurring_contract('user-id')
|
223
|
+
end
|
224
|
+
|
225
|
+
it "performs a `disable recurring contract' request for a specific detail" do
|
226
|
+
should_map_shortcut_to(:disable, :shopper => { :reference => 'user-id' }, :recurring_detail_reference => 'detail-id')
|
227
|
+
Adyen::API.disable_recurring_contract('user-id', 'detail-id')
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|