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