fingertips-adyen 0.3.7.20100917
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/.gitignore +8 -0
- data/LICENSE +20 -0
- data/README.rdoc +40 -0
- data/Rakefile +5 -0
- data/adyen.gemspec +30 -0
- data/init.rb +1 -0
- data/lib/adyen.rb +77 -0
- data/lib/adyen/api.rb +343 -0
- data/lib/adyen/encoding.rb +21 -0
- data/lib/adyen/form.rb +336 -0
- data/lib/adyen/formatter.rb +37 -0
- data/lib/adyen/matchers.rb +105 -0
- data/lib/adyen/notification.rb +151 -0
- data/spec/adyen_spec.rb +86 -0
- data/spec/api_spec.rb +562 -0
- data/spec/form_spec.rb +152 -0
- data/spec/notification_spec.rb +97 -0
- data/spec/spec_helper.rb +12 -0
- data/tasks/github-gem.rake +371 -0
- metadata +132 -0
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 - 2009 Willem van Bergen and Michel Barbosa
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
= Adyen
|
2
|
+
|
3
|
+
Package to simplify including the Adyen payments services into a Ruby on Rails application.
|
4
|
+
|
5
|
+
Adyen integration relies on three modes of communication between Adyen, your server and
|
6
|
+
your client/customer:
|
7
|
+
|
8
|
+
* Client-to-Adyen communication using forms and redirects.
|
9
|
+
* Adyen-to-server communications using notifications.
|
10
|
+
* Server-to-Adyen communication using SOAP services.
|
11
|
+
|
12
|
+
This library aims to ease the implementation of all these modes into your application.
|
13
|
+
Moreover, it provides matchers, assertions and mocks to make it easier to implement an
|
14
|
+
automated test suite to assert the integration is working correctly.
|
15
|
+
|
16
|
+
== Installation
|
17
|
+
|
18
|
+
Add the following line to your <tt>environment.rb</tt> and run <tt>rake gems:install</tt>
|
19
|
+
to make the Adyen functionality available in your Rails project:
|
20
|
+
|
21
|
+
config.gem 'adyen', :source => 'http://gemcutter.org
|
22
|
+
|
23
|
+
You can also install it as a Rails plugin (*deprecated*):
|
24
|
+
|
25
|
+
script/plugin install git://github.com/wvanbergen/adyen.git
|
26
|
+
|
27
|
+
== Usage
|
28
|
+
|
29
|
+
See the project wiki on http://wiki.github.com/wvanbergen/adyen to get started. Complete
|
30
|
+
RDoc documentation for the project can be found on http://rdoc.info/projects/wvanbergen/adyen.
|
31
|
+
|
32
|
+
* For more information about Adyen, see http://www.adyen.com
|
33
|
+
* For more information about integrating Adyen, see their manuals at
|
34
|
+
http://support.adyen.com/links/documentation
|
35
|
+
|
36
|
+
== About
|
37
|
+
|
38
|
+
This package is written by Michel Barbosa and Willem van Bergen for Floorplanner.com, and
|
39
|
+
made public under the MIT license (see LICENSE). It comes without warranty of any kind, so
|
40
|
+
use at your own risk.
|
data/Rakefile
ADDED
data/adyen.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'fingertips-adyen'
|
3
|
+
s.version = "0.3.7.20100917"
|
4
|
+
s.date = "2010-07-21"
|
5
|
+
|
6
|
+
s.summary = "Integrate Adyen payment services in you Ruby on Rails application."
|
7
|
+
s.description = <<-EOS
|
8
|
+
Package to simplify including the Adyen payments services into a Ruby on Rails application.
|
9
|
+
The package provides functionality to create payment forms, handling and storing notifications
|
10
|
+
sent by Adyen and consuming the SOAP services provided by Adyen. Moreover, it contains helper
|
11
|
+
methods, mocks and matchers to simpify writing tests/specsfor your code.
|
12
|
+
EOS
|
13
|
+
|
14
|
+
s.authors = ['Willem van Bergen', 'Michel Barbosa', 'Eloy Duran']
|
15
|
+
s.email = ['willem@vanbergen.org', 'cicaboo@gmail.com', 'eloy.de.enige@gmail.com']
|
16
|
+
s.homepage = 'http://wiki.github.com/wvanbergen/adyen'
|
17
|
+
|
18
|
+
s.add_development_dependency('rspec', '>= 1.1.4')
|
19
|
+
s.add_development_dependency('git', '>= 1.1.0')
|
20
|
+
|
21
|
+
s.requirements << 'Handsoap is required for accessing the SOAP services. See http://github.com/troelskn/handsoap.'
|
22
|
+
s.requirements << 'LibXML is required for using the RSpec matchers.'
|
23
|
+
s.requirements << 'ActiveRecord is required for storing the notifications in your database.'
|
24
|
+
|
25
|
+
s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
|
26
|
+
s.extra_rdoc_files = ['README.rdoc']
|
27
|
+
|
28
|
+
s.files = %w(spec/spec_helper.rb spec/adyen_spec.rb lib/adyen/form.rb .gitignore spec/notification_spec.rb lib/adyen/api.rb LICENSE spec/api_spec.rb init.rb adyen.gemspec Rakefile spec/form_spec.rb README.rdoc lib/adyen/notification.rb lib/adyen/formatter.rb tasks/github-gem.rake lib/adyen/encoding.rb lib/adyen/matchers.rb lib/adyen.rb)
|
29
|
+
s.test_files = %w(spec/adyen_spec.rb spec/notification_spec.rb spec/api_spec.rb spec/form_spec.rb)
|
30
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'adyen'
|
data/lib/adyen.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# The Adyen module is the container module for all Adyen related functionality,
|
2
|
+
# which is implemented in submodules. This module only contains some global
|
3
|
+
# configuration methods.
|
4
|
+
#
|
5
|
+
# The most important submodules are:
|
6
|
+
# * {Adyen::Form} for generating payment form fields, generating redirect URLs
|
7
|
+
# to the Adyen payment system, and generating and checking of signatures.
|
8
|
+
# * {Adyen::Notification} for handling notifications sent by Adyen to your servers.
|
9
|
+
# * {Adyen::SOAP} for communicating with the Adyen SOAP services for payment
|
10
|
+
# maintenance and issuing recurring payments.
|
11
|
+
module Adyen
|
12
|
+
|
13
|
+
# Version constant for the Adyen plugin.
|
14
|
+
# DO NOT CHANGE THIS VALUE BY HAND. It will be updated automatically by
|
15
|
+
# the gem:release rake task.
|
16
|
+
VERSION = "0.3.7.20100917"
|
17
|
+
|
18
|
+
# Loads configuration settings from a Hash.
|
19
|
+
#
|
20
|
+
# @param [Hash] hash The (nested Hash) with configuration variables.
|
21
|
+
# @param [Module] mod The current working module. This parameter is used
|
22
|
+
# to recursively traverse the hash for submodules.
|
23
|
+
# @raise [StandardError] An exception is raised of an unkown configuration
|
24
|
+
# setting is encountered in the hash.
|
25
|
+
def self.load_config(hash, mod = Adyen)
|
26
|
+
hash.each do |key, value|
|
27
|
+
if key.to_s =~ /^[a-z]/ && mod.respond_to?(:"#{key}=")
|
28
|
+
mod.send(:"#{key}=", value)
|
29
|
+
elsif key.to_s =~ /^[A-Z]/
|
30
|
+
self.load_config(value, mod.const_get(key))
|
31
|
+
else
|
32
|
+
raise "Unknown configuration variable: '#{key}' for #{mod}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# The Rails environment for which to use to Adyen "live" environment.
|
38
|
+
LIVE_RAILS_ENVIRONMENTS = ['production']
|
39
|
+
|
40
|
+
# Setter voor the current Adyen environment.
|
41
|
+
# @param ['test', 'live'] env The Adyen environment to use
|
42
|
+
def self.environment=(env)
|
43
|
+
@environment = env
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the current Adyen environment, either test or live.
|
47
|
+
#
|
48
|
+
# It will return the +override+ value if set, it will return the value set
|
49
|
+
# using {Adyen.environment=} otherwise. If this value also isn't set, the
|
50
|
+
# environment is determined with {Adyen.autodetect_environment}.
|
51
|
+
#
|
52
|
+
# @param ['test', 'live'] override An environment to override the default with.
|
53
|
+
# @return ['test', 'live'] The Adyen environment that is currently being used.
|
54
|
+
def self.environment(override = nil)
|
55
|
+
override || @environment || Adyen.autodetect_environment
|
56
|
+
end
|
57
|
+
|
58
|
+
# Autodetects the Adyen environment based on the RAILS_ENV constant.
|
59
|
+
# @return ['test', 'live'] The Adyen environment that corresponds to the Rails environment
|
60
|
+
def self.autodetect_environment
|
61
|
+
(defined?(RAILS_ENV) && Adyen::LIVE_RAILS_ENVIRONMENTS.include?(RAILS_ENV.to_s.downcase)) ? 'live' : 'test'
|
62
|
+
end
|
63
|
+
|
64
|
+
# Loads submodules on demand, so that dependencies are not required.
|
65
|
+
# @param [Symbol] sym The name of the submodule
|
66
|
+
# @return [Module] The actual loaded submodule.
|
67
|
+
# @raise [LoadError, NameError] If the submodule cannot be loaded
|
68
|
+
def self.const_missing(sym)
|
69
|
+
require "adyen/#{sym.to_s.downcase}"
|
70
|
+
return Adyen.const_get(sym)
|
71
|
+
rescue Exception
|
72
|
+
super(sym)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
require 'adyen/encoding'
|
77
|
+
require 'adyen/formatter'
|
data/lib/adyen/api.rb
ADDED
@@ -0,0 +1,343 @@
|
|
1
|
+
require "net/https"
|
2
|
+
|
3
|
+
module Adyen
|
4
|
+
module API
|
5
|
+
class << self
|
6
|
+
# Username for the HTTP Basic Authentication that Adyen uses. Your username
|
7
|
+
# should be something like +ws@Company.MyAccount+
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :username
|
10
|
+
|
11
|
+
# Password for the HTTP Basic Authentication that Adyen uses. You can choose
|
12
|
+
# your password yourself in the user management tool of the merchant area.
|
13
|
+
# @return [String]
|
14
|
+
attr_accessor :password
|
15
|
+
|
16
|
+
attr_accessor :default_params
|
17
|
+
end
|
18
|
+
|
19
|
+
self.default_params = {}
|
20
|
+
|
21
|
+
#
|
22
|
+
# Shortcut methods
|
23
|
+
#
|
24
|
+
|
25
|
+
def self.authorise_payment(params = {})
|
26
|
+
PaymentService.new(params).authorise_payment
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.authorise_recurring_payment(params = {})
|
30
|
+
PaymentService.new(params).authorise_recurring_payment
|
31
|
+
end
|
32
|
+
|
33
|
+
# TODO: the rest
|
34
|
+
|
35
|
+
#
|
36
|
+
# The actual classes
|
37
|
+
#
|
38
|
+
|
39
|
+
class SimpleSOAPClient
|
40
|
+
# from http://curl.haxx.se/ca/cacert.pem
|
41
|
+
CACERT = File.expand_path('../../../support/cacert.pem', __FILE__)
|
42
|
+
|
43
|
+
def self.endpoint
|
44
|
+
@endpoint ||= URI.parse(const_get('ENDPOINT_URI') % Adyen.environment)
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_reader :params
|
48
|
+
|
49
|
+
def initialize(params = {})
|
50
|
+
@params = API.default_params.merge(params)
|
51
|
+
end
|
52
|
+
|
53
|
+
def call_webservice_action(action, data)
|
54
|
+
endpoint = self.class.endpoint
|
55
|
+
|
56
|
+
post = Net::HTTP::Post.new(endpoint.path, 'Accept' => 'text/xml', 'Content-Type' => 'text/xml; charset=utf-8', 'SOAPAction' => action)
|
57
|
+
post.basic_auth(API.username, API.password)
|
58
|
+
post.body = data
|
59
|
+
|
60
|
+
request = Net::HTTP.new(endpoint.host, endpoint.port)
|
61
|
+
request.use_ssl = true
|
62
|
+
request.ca_file = CACERT
|
63
|
+
request.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
64
|
+
|
65
|
+
request.start do |http|
|
66
|
+
response = http.request(post)
|
67
|
+
# TODO: handle not 2xx responses
|
68
|
+
#p response
|
69
|
+
XMLQuerier.new(response.body)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class PaymentService < SimpleSOAPClient
|
75
|
+
ENDPOINT_URI = 'https://pal-%s.adyen.com/pal/servlet/soap/Payment'
|
76
|
+
|
77
|
+
def authorise_payment
|
78
|
+
make_payment_request(authorise_payment_request_body)
|
79
|
+
end
|
80
|
+
|
81
|
+
def authorise_recurring_payment
|
82
|
+
make_payment_request(authorise_recurring_payment_request_body)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def make_payment_request(data)
|
88
|
+
response = call_webservice_action('authorise', data)
|
89
|
+
response.xpath('//payment:authoriseResponse/payment:paymentResult') do |result|
|
90
|
+
{
|
91
|
+
:psp_reference => result.text('./payment:pspReference'),
|
92
|
+
:result_code => result.text('./payment:resultCode'),
|
93
|
+
:auth_code => result.text('./payment:authCode'),
|
94
|
+
:refusal_reason => result.text('./payment:refusalReason')
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def authorise_payment_request_body
|
100
|
+
content = card_partial
|
101
|
+
content << RECURRING_PARTIAL if @params[:recurring]
|
102
|
+
payment_request_body(content)
|
103
|
+
end
|
104
|
+
|
105
|
+
def authorise_recurring_payment_request_body
|
106
|
+
content = RECURRING_PAYMENT_BODY_PARTIAL % (@params[:recurring_detail_reference] || 'LATEST')
|
107
|
+
payment_request_body(content)
|
108
|
+
end
|
109
|
+
|
110
|
+
def payment_request_body(content)
|
111
|
+
content << amount_partial
|
112
|
+
content << shopper_partial if @params[:shopper]
|
113
|
+
LAYOUT % [@params[:merchant_account], @params[:reference], content]
|
114
|
+
end
|
115
|
+
|
116
|
+
def amount_partial
|
117
|
+
AMOUNT_PARTIAL % @params[:amount].values_at(:currency, :value)
|
118
|
+
end
|
119
|
+
|
120
|
+
def card_partial
|
121
|
+
card = @params[:card].values_at(:holder_name, :number, :cvc, :expiry_year)
|
122
|
+
card << @params[:card][:expiry_month].to_i
|
123
|
+
CARD_PARTIAL % card
|
124
|
+
end
|
125
|
+
|
126
|
+
def shopper_partial
|
127
|
+
@params[:shopper].map { |k, v| SHOPPER_PARTIALS[k] % v }.join("\n")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class RecurringService < SimpleSOAPClient
|
132
|
+
ENDPOINT_URI = 'https://pal-%s.adyen.com/pal/servlet/soap/Recurring'
|
133
|
+
|
134
|
+
# TODO: rename to list_details and make shortcut method take the only necessary param
|
135
|
+
def list
|
136
|
+
response = call_webservice_action('listRecurringDetails', list_request_body)
|
137
|
+
response.xpath('//recurring:listRecurringDetailsResponse/recurring:result') do |result|
|
138
|
+
{
|
139
|
+
:creation_date => DateTime.parse(result.text('./recurring:creationDate')),
|
140
|
+
:details => result.xpath('.//recurring:RecurringDetail').map { |node| parse_recurring_detail(node) },
|
141
|
+
:last_known_shopper_email => result.text('./recurring:lastKnownShopperEmail'),
|
142
|
+
:shopper_reference => result.text('./recurring:shopperReference')
|
143
|
+
}
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def list_request_body
|
150
|
+
LAYOUT % [@params[:merchant_account], @params[:shopper][:reference]]
|
151
|
+
end
|
152
|
+
|
153
|
+
# @todo add support for elv
|
154
|
+
def parse_recurring_detail(node)
|
155
|
+
result = {
|
156
|
+
:recurring_detail_reference => node.text('./recurring:recurringDetailReference'),
|
157
|
+
:variant => node.text('./recurring:variant'),
|
158
|
+
:creation_date => DateTime.parse(node.text('./recurring:creationDate'))
|
159
|
+
}
|
160
|
+
|
161
|
+
card = node.xpath('./recurring:card')
|
162
|
+
if card.children.empty?
|
163
|
+
result[:bank] = parse_bank_details(node.xpath('./recurring:bank'))
|
164
|
+
else
|
165
|
+
result[:card] = parse_card_details(card)
|
166
|
+
end
|
167
|
+
|
168
|
+
result
|
169
|
+
end
|
170
|
+
|
171
|
+
def parse_card_details(card)
|
172
|
+
{
|
173
|
+
:expiry_date => Date.new(card.text('./payment:expiryYear').to_i, card.text('./payment:expiryMonth').to_i, -1),
|
174
|
+
:holder_name => card.text('./payment:holderName'),
|
175
|
+
:number => card.text('./payment:number')
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
def parse_bank_details(bank)
|
180
|
+
{
|
181
|
+
:bank_account_number => bank.text('./payment:bankAccountNumber'),
|
182
|
+
:bank_location_id => bank.text('./payment:bankLocationId'),
|
183
|
+
:bank_name => bank.text('./payment:bankName'),
|
184
|
+
:bic => bank.text('./payment:bic'),
|
185
|
+
:country_code => bank.text('./payment:countryCode'),
|
186
|
+
:iban => bank.text('./payment:iban'),
|
187
|
+
:owner_name => bank.text('./payment:ownerName')
|
188
|
+
}
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class XMLQuerier
|
193
|
+
NS = {
|
194
|
+
'payment' => 'http://payment.services.adyen.com',
|
195
|
+
'recurring' => 'http://recurring.services.adyen.com',
|
196
|
+
'common' => 'http://common.services.adyen.com'
|
197
|
+
}
|
198
|
+
|
199
|
+
class << self
|
200
|
+
attr_accessor :backend
|
201
|
+
|
202
|
+
def backend=(backend)
|
203
|
+
@backend = backend
|
204
|
+
class_eval do
|
205
|
+
private
|
206
|
+
if backend == :nokogiri
|
207
|
+
def document_for_xml(xml)
|
208
|
+
Nokogiri::XML::Document.parse(xml)
|
209
|
+
end
|
210
|
+
def perform_xpath(query)
|
211
|
+
@node.xpath(query, NS)
|
212
|
+
end
|
213
|
+
else
|
214
|
+
def document_for_xml(xml)
|
215
|
+
REXML::Document.new(xml)
|
216
|
+
end
|
217
|
+
def perform_xpath(query)
|
218
|
+
REXML::XPath.match(@node, query, NS)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
begin
|
226
|
+
require 'nokogiri'
|
227
|
+
self.backend = :nokogiri
|
228
|
+
rescue LoadError
|
229
|
+
require 'rexml/document'
|
230
|
+
self.backend = :rexml
|
231
|
+
end
|
232
|
+
|
233
|
+
def initialize(data)
|
234
|
+
@node = data.is_a?(String) ? document_for_xml(data) : data
|
235
|
+
end
|
236
|
+
|
237
|
+
def xpath(query)
|
238
|
+
result = self.class.new(perform_xpath(query))
|
239
|
+
block_given? ? yield(result) : result
|
240
|
+
end
|
241
|
+
|
242
|
+
def text(query)
|
243
|
+
xpath("#{query}/text()").to_s
|
244
|
+
end
|
245
|
+
|
246
|
+
def children
|
247
|
+
@node.first.children
|
248
|
+
end
|
249
|
+
|
250
|
+
def empty?
|
251
|
+
@node.empty?
|
252
|
+
end
|
253
|
+
|
254
|
+
def to_s
|
255
|
+
@node.to_s
|
256
|
+
end
|
257
|
+
|
258
|
+
def map(&block)
|
259
|
+
@node.map { |n| self.class.new(n) }.map(&block)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
########################
|
266
|
+
#
|
267
|
+
# XML template constants
|
268
|
+
#
|
269
|
+
########################
|
270
|
+
|
271
|
+
module Adyen
|
272
|
+
module API
|
273
|
+
class PaymentService
|
274
|
+
LAYOUT = <<EOS
|
275
|
+
<?xml version="1.0"?>
|
276
|
+
<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">
|
277
|
+
<soap:Body>
|
278
|
+
<ns1:authorise xmlns:ns1="http://payment.services.adyen.com">
|
279
|
+
<ns1:paymentRequest>
|
280
|
+
<merchantAccount xmlns="http://payment.services.adyen.com">%s</merchantAccount>
|
281
|
+
<reference xmlns="http://payment.services.adyen.com">%s</reference>
|
282
|
+
%s
|
283
|
+
</ns1:paymentRequest>
|
284
|
+
</ns1:authorise>
|
285
|
+
</soap:Body>
|
286
|
+
</soap:Envelope>
|
287
|
+
EOS
|
288
|
+
|
289
|
+
AMOUNT_PARTIAL = <<EOS
|
290
|
+
<amount xmlns="http://payment.services.adyen.com">
|
291
|
+
<currency xmlns="http://common.services.adyen.com">%s</currency>
|
292
|
+
<value xmlns="http://common.services.adyen.com">%s</value>
|
293
|
+
</amount>
|
294
|
+
EOS
|
295
|
+
|
296
|
+
CARD_PARTIAL = <<EOS
|
297
|
+
<card xmlns="http://payment.services.adyen.com">
|
298
|
+
<holderName>%s</holderName>
|
299
|
+
<number>%s</number>
|
300
|
+
<cvc>%s</cvc>
|
301
|
+
<expiryYear>%s</expiryYear>
|
302
|
+
<expiryMonth>%02d</expiryMonth>
|
303
|
+
</card>
|
304
|
+
EOS
|
305
|
+
|
306
|
+
RECURRING_PARTIAL = <<EOS
|
307
|
+
<recurring xmlns="http://recurring.services.adyen.com">
|
308
|
+
<contract xmlns="http://payment.services.adyen.com">RECURRING</contract>
|
309
|
+
</recurring>
|
310
|
+
EOS
|
311
|
+
|
312
|
+
RECURRING_PAYMENT_BODY_PARTIAL = RECURRING_PARTIAL + <<EOS
|
313
|
+
<ns1:selectedRecurringDetailReference>%s</ns1:selectedRecurringDetailReference>
|
314
|
+
<ns1:shopperInteraction>ContAuth</ns1:shopperInteraction>
|
315
|
+
EOS
|
316
|
+
|
317
|
+
SHOPPER_PARTIALS = {
|
318
|
+
:reference => ' <shopperReference xmlns="http://payment.services.adyen.com">%s</shopperReference>',
|
319
|
+
:email => ' <shopperEmail xmlns="http://payment.services.adyen.com">%s</shopperEmail>',
|
320
|
+
:ip => ' <shopperIP xmlns="http://payment.services.adyen.com">%s</shopperIP>',
|
321
|
+
}
|
322
|
+
end
|
323
|
+
|
324
|
+
class RecurringService
|
325
|
+
LAYOUT = <<EOS
|
326
|
+
<?xml version="1.0"?>
|
327
|
+
<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">
|
328
|
+
<soap:Body>
|
329
|
+
<ns1:listRecurringDetails xmlns:ns1="http://recurring.services.adyen.com">
|
330
|
+
<ns1:request>
|
331
|
+
<ns1:recurring>
|
332
|
+
<ns1:contract>RECURRING</ns1:contract>
|
333
|
+
</ns1:recurring>
|
334
|
+
<ns1:merchantAccount>%s</ns1:merchantAccount>
|
335
|
+
<ns1:shopperReference>%s</ns1:shopperReference>
|
336
|
+
</ns1:request>
|
337
|
+
</ns1:listRecurringDetails>
|
338
|
+
</soap:Body>
|
339
|
+
</soap:Envelope>
|
340
|
+
EOS
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|