adyen 0.2.3 → 0.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.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  /pkg
3
3
  /doc
4
4
  adyen-*.gem
5
+ .yardoc
@@ -26,7 +26,8 @@ You can also install it as a Rails plugin (*deprecated*):
26
26
 
27
27
  == Usage
28
28
 
29
- See the project wiki on http://wiki.github.com/wvanbergen/adyen to get started.
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.
30
31
 
31
32
  * For more information about Adyen, see http://www.adyen.com
32
33
  * For more information about integrating Adyen, see their manuals at
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'adyen'
3
- s.version = "0.2.3"
4
- s.date = "2009-12-11"
3
+ s.version = "0.3.0"
4
+ s.date = "2009-12-14"
5
5
 
6
6
  s.summary = "Integrate Adyen payment services in you Ruby on Rails application."
7
7
  s.description = <<-EOS
@@ -1,20 +1,28 @@
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.
1
11
  module Adyen
2
12
 
3
13
  # Loads configuration settings from a Hash.
4
14
  #
5
- # This method is called recursively for every module. The second
6
- # argument is used to denote the current working module.
15
+ # @param [Hash] hash The (nested Hash) with configuration variables.
16
+ # @param [Module] mod The current working module. This parameter is used
17
+ # to recursively traverse the hash for submodules.
18
+ # @raise [StandardError] An exception is raised of an unkown configuration
19
+ # setting is encountered in the hash.
7
20
  def self.load_config(hash, mod = Adyen)
8
21
  hash.each do |key, value|
9
22
  if key.to_s =~ /^[a-z]/ && mod.respond_to?(:"#{key}=")
10
23
  mod.send(:"#{key}=", value)
11
24
  elsif key.to_s =~ /^[A-Z]/
12
- begin
13
- submodule = mod.const_get(key)
14
- rescue LoadError => e
15
- raise "Unknown Adyen module to configure: #{mod.name}::#{key}"
16
- end
17
- self.load_config(value, submodule)
25
+ self.load_config(value, mod.const_get(key))
18
26
  else
19
27
  raise "Unknown configuration variable: '#{key}' for #{mod}"
20
28
  end
@@ -25,27 +33,37 @@ module Adyen
25
33
  LIVE_RAILS_ENVIRONMENTS = ['production']
26
34
 
27
35
  # Setter voor the current Adyen environment.
28
- # Must be either 'test' or 'live'
36
+ # @param ['test', 'live'] env The Adyen environment to use
29
37
  def self.environment=(env)
30
38
  @environment = env
31
39
  end
32
40
 
33
- # Returns the current Adyen environment.
34
- # Returns either 'test' or 'live'.
41
+ # Returns the current Adyen environment, either test or live.
42
+ #
43
+ # It will return the +override+ value if set, it will return the value set
44
+ # using {Adyen.environment=} otherwise. If this value also isn't set, the
45
+ # environemtn is determined with {Adyen.autodetect_environment}.
46
+ #
47
+ # @param ['test', 'live'] override An environemt to override the default with.
48
+ # @return ['test', 'live'] The Adyen environment that is currently being used.
35
49
  def self.environment(override = nil)
36
50
  override || @environment || Adyen.autodetect_environment
37
51
  end
38
52
 
39
- # Autodetects the Adyen environment based on the RAILS_ENV constant
53
+ # Autodetects the Adyen environment based on the RAILS_ENV constant.
54
+ # @return ['test', 'live'] The Adyen environment that corresponds to the Rails environment
40
55
  def self.autodetect_environment
41
56
  (defined?(RAILS_ENV) && Adyen::LIVE_RAILS_ENVIRONMENTS.include?(RAILS_ENV.to_s.downcase)) ? 'live' : 'test'
42
57
  end
43
58
 
44
59
  # Loads submodules on demand, so that dependencies are not required.
60
+ # @param [Symbol] sym The name of the submodule
61
+ # @return [Module] The actual loaded submodule.
62
+ # @raise [LoadError, NameError] If the submodule cannot be loaded
45
63
  def self.const_missing(sym)
46
64
  require "adyen/#{sym.to_s.downcase}"
47
65
  return Adyen.const_get(sym)
48
- rescue Exception => e
66
+ rescue Exception
49
67
  super(sym)
50
68
  end
51
69
  end
@@ -1,6 +1,25 @@
1
1
  require 'action_view'
2
2
 
3
3
  module Adyen
4
+
5
+ # The Adyen::Form module contains all functionality that is used to send payment requests
6
+ # to the Adyen payment system, using either a HTML form (see {Adyen::Form.hidden_fields})
7
+ # or a HTTP redirect (see {Adyen::Form.redirect_url}).
8
+ #
9
+ # Moreover, this module contains a method ({Adyen::Form.redirect_signature_check}) to
10
+ # check the request that is made to your website after the visitor has made his payment
11
+ # on the Adyen system for genuinity.
12
+ #
13
+ # You can use different skins in Adyen to define different payment environments. You can
14
+ # register these skins under a custom name in the module. The other methods will automatically
15
+ # use this information (i.e. the skin code and the shared secret) if it is available.
16
+ # Otherwise, you have to provide it yourself for every method call you make. See
17
+ # {Adyen::Form.register_skin} for more information.
18
+ #
19
+ # @see Adyen::Form.register_skin
20
+ # @see Adyen::Form.hidden_fields
21
+ # @see Adyen::Form.redirect_url
22
+ # @see Adyen::Form.redirect_signature_check
4
23
  module Form
5
24
 
6
25
  extend ActionView::Helpers::TagHelper
@@ -9,41 +28,75 @@ module Adyen
9
28
  # SKINS
10
29
  ######################################################
11
30
 
31
+ # Returns all registered skins and their accompanying skin code and shared secret.
32
+ # @return [Hash] The hash of registered skins.
12
33
  def self.skins
13
34
  @skins ||= {}
14
35
  end
15
36
 
37
+ # Sets the registered skins.
38
+ # @param [Hash<Symbol, Hash>] hash A hash with the skin name as key and the skin parameter hash
39
+ # (which should include +:skin_code+ and +:shared_secret+) as value.
40
+ # @see Adyen::Form.register_skin
16
41
  def self.skins=(hash)
17
42
  @skins = hash.inject({}) do |skins, (name, skin)|
18
43
  skins[name.to_sym] = skin.merge(:name => name.to_sym)
19
44
  skins
20
45
  end
21
46
  end
22
-
47
+
48
+ # Registers a skin for later use.
49
+ #
50
+ # You can store a skin using a self defined symbol. Once the skin is registered,
51
+ # you can refer to it using this symbol instead of the hard-to-remember skin code.
52
+ # Moreover, the skin's shared_secret will be looked up automatically for calculting
53
+ # signatures.
54
+ #
55
+ # @example
56
+ # Adyen::Form.register_skin(:my_skin, 'dsfH67PO', 'Dfs*7uUln9')
57
+ # @param [Symbol] name The name of the skin.
58
+ # @param [String] skin_code The skin code for this skin, as defined by Adyen.
59
+ # @param [String] shared_secret The shared secret used for signature calculation.
60
+ # @see Adyen.load_config
23
61
  def self.register_skin(name, skin_code, shared_secret)
24
62
  self.skins[name.to_sym] = {:name => name.to_sym, :skin_code => skin_code, :shared_secret => shared_secret }
25
63
  end
26
64
 
65
+ # Returns skin information given a skin name.
66
+ # @param [Symbol] skin_name The name of the skin
67
+ # @return [Hash, nil] A hash with the skin information, or nil if not found.
27
68
  def self.skin_by_name(skin_name)
28
69
  self.skins[skin_name.to_sym]
29
70
  end
30
-
71
+
72
+ # Returns skin information given a skin code.
73
+ # @param [String] skin_code The skin code of the skin
74
+ # @return [Hash, nil] A hash with the skin information, or nil if not found.
31
75
  def self.skin_by_code(skin_code)
32
- self.skins.detect { |(name, skin)| skin[:skin_code] == skin_code }.last rescue nil
76
+ self.skins.detect { |(name, skin)| skin[:skin_code] == skin_code }.last rescue nil
33
77
  end
34
-
78
+
79
+ # Returns the shared secret belonging to a skin code.
80
+ # @param [String] skin_code The skin code of the skin
81
+ # @return [String, nil] The shared secret for the skin, or nil if not found.
35
82
  def self.lookup_shared_secret(skin_code)
36
83
  skin = skin_by_code(skin_code)[:shared_secret] rescue nil
37
- end
38
-
84
+ end
85
+
39
86
  ######################################################
40
87
  # DEFAULT FORM / REDIRECT PARAMETERS
41
- ######################################################
88
+ ######################################################
42
89
 
90
+ # Returns the default parameters to use, unless they are overridden.
91
+ # @see Adyen::Form.default_parameters
92
+ # @return [Hash] The hash of default parameters
43
93
  def self.default_parameters
44
94
  @default_arguments ||= {}
45
95
  end
46
96
 
97
+ # Sets the default parameters to use.
98
+ # @see Adyen::Form.default_parameters
99
+ # @param [Hash] hash The hash of default parameters
47
100
  def self.default_parameters=(hash)
48
101
  @default_arguments = hash
49
102
  end
@@ -52,18 +105,34 @@ module Adyen
52
105
  # ADYEN FORM URL
53
106
  ######################################################
54
107
 
108
+ # The URL of the Adyen payment system that still requires the current
109
+ # Adyen enviroment to be filled in.
55
110
  ACTION_URL = "https://%s.adyen.com/hpp/select.shtml"
56
111
 
112
+ # Returns the URL of the Adyen payment system, adjusted for an Adyen environment.
113
+ #
114
+ # @param [String] environment The Adyen environment to use. This parameter can be
115
+ # left out, in which case the 'current' environment will be used.
116
+ # @return [String] The absolute URL of the Adyen payment system that can be used
117
+ # for payment forms or redirects.
118
+ # @see Adyen::Form.environment
119
+ # @see Adyen::Form.redirect_url
57
120
  def self.url(environment = nil)
58
- environment ||= Adyen.environment(environment)
121
+ environment ||= Adyen.environment
59
122
  Adyen::Form::ACTION_URL % environment.to_s
60
123
  end
61
124
 
62
-
63
125
  ######################################################
64
126
  # POSTING/REDIRECTING TO ADYEN
65
127
  ######################################################
66
128
 
129
+ # Transforms the payment parameters hash to be in the correct format.
130
+ # It will also include the default_parameters hash. Finally, switches
131
+ # the +:skin+ parameter out for the +:skin_code+ and +:shared_secret+
132
+ # parameter using the list of registered skins.
133
+ #
134
+ # @private
135
+ # @param [Hash] parameters The payment parameters hash to transform
67
136
  def self.do_parameter_transformations!(parameters = {})
68
137
  raise "YENs are not yet supported!" if parameters[:currency_code] == 'JPY' # TODO: fixme
69
138
 
@@ -80,26 +149,90 @@ module Adyen
80
149
  end
81
150
  end
82
151
 
83
- def self.payment_parameters(parameters = {})
152
+ # Transforms the payment parameters to be in the correct format and calculates the merchant
153
+ # signature parameter. It also does some basic health checks on the parameters hash.
154
+ #
155
+ # @param [Hash] parameters The payment parameters. The parameters set in the
156
+ # {Adyen::Form.default_parameters} hash will be included automatically.
157
+ # @param [String] shared_secret The shared secret that should be used to calculate
158
+ # the payment request signature. This parameter can be left if the skin that is
159
+ # used is registered (see {Adyen::Form.register_skin}), or if the shared secret
160
+ # is provided as the +:shared_secret+ parameter.
161
+ # @return [Hash] The payment parameters with the +:merchant_signature+ parameter set.
162
+ # @raise [StandardError] Thrown if some parameter health check fails.
163
+ def self.payment_parameters(parameters = {}, shared_secret = nil)
84
164
  do_parameter_transformations!(parameters)
85
165
 
86
166
  raise "Cannot generate form: :currency code attribute not found!" unless parameters[:currency_code]
87
167
  raise "Cannot generate form: :payment_amount code attribute not found!" unless parameters[:payment_amount]
88
168
  raise "Cannot generate form: :merchant_account attribute not found!" unless parameters[:merchant_account]
89
169
  raise "Cannot generate form: :skin_code attribute not found!" unless parameters[:skin_code]
90
- raise "Cannot generate form: :shared_secret signing secret not provided!" unless parameters[:shared_secret]
91
170
 
92
- # Merchant signature
93
- parameters[:merchant_sig] = calculate_signature(parameters)
94
- return parameters
171
+ # Calculate the merchant signature using the shared secret.
172
+ shared_secret ||= parameters.delete(:shared_secret)
173
+ raise "Cannot calculate payment request signature without shared secret!" unless shared_secret
174
+ parameters[:merchant_sig] = calculate_signature(parameters, shared_secret)
175
+
176
+ return parameters
95
177
  end
96
178
 
179
+ # Returns an absolute URL to the Adyen payment system, with the payment parameters included
180
+ # as GET parameters in the URL. The URL also depends on the current Adyen enviroment.
181
+ #
182
+ # The payment parameters that are provided to this method will be merged with the
183
+ # {Adyen::Form.default_parameters} hash. The default parameter values will be overrided
184
+ # if another value is provided to this method.
185
+ #
186
+ # You do not have to provide the +:merchant_sig+ parameter: it will be calculated automatically
187
+ # if you provide either a registered skin name as the +:skin+ parameter or provide both the
188
+ # +:skin_code+ and +:shared_secret+ parameters.
189
+ #
190
+ # Note that Internet Explorer has a maximum length for URLs it can handle (2083 characters).
191
+ # Make sure that the URL is not longer than this limit if you want your site to work in IE.
192
+ #
193
+ # @example
194
+ #
195
+ # def pay
196
+ # # Genarate a URL to redirect to Adyen's payment system.
197
+ # adyen_url = Adyen::Form.redirect_url(:skin => :my_skin, :currency_code => 'USD',
198
+ # :payment_amount => 1000, merchant_account => 'MyMerchant', ... )
199
+ #
200
+ # respond_to do |format|
201
+ # format.html { redirect_to(adyen_url) }
202
+ # end
203
+ # end
204
+ #
205
+ # @param [Hash] parameters The payment parameters to include in the payment request.
206
+ # @return [String] An absolute URL to redirect to the Adyen payment system.
97
207
  def self.redirect_url(parameters = {})
98
- self.url + '?' + payment_parameters(parameters).map { |(k, v)| "#{k.to_s.camelize(:lower)}=#{CGI.escape(v.to_s)}" }.join('&')
208
+ self.url + '?' + payment_parameters(parameters).map { |(k, v)|
209
+ "#{k.to_s.camelize(:lower)}=#{CGI.escape(v.to_s)}" }.join('&')
99
210
  end
100
-
211
+
212
+ # Returns a HTML snippet of hidden INPUT tags with the provided payment parameters.
213
+ # The snippet can be included in a payment form that POSTs to the Adyen payment system.
214
+ #
215
+ # The payment parameters that are provided to this method will be merged with the
216
+ # {Adyen::Form.default_parameters} hash. The default parameter values will be overrided
217
+ # if another value is provided to this method.
218
+ #
219
+ # You do not have to provide the +:merchant_sig+ parameter: it will be calculated automatically
220
+ # if you provide either a registered skin name as the +:skin+ parameter or provide both the
221
+ # +:skin_code+ and +:shared_secret+ parameters.
222
+ #
223
+ # @example
224
+ # <% form_tag(Adyen::Form.url) do %>
225
+ # <%= Adyen::Form.hidden_fields(:skin => :my_skin, :currency_code => 'USD',
226
+ # :payment_amount => 1000, ...) %>
227
+ # <%= submit_tag("Pay invoice")
228
+ # <% end %>
229
+ #
230
+ # @param [Hash] parameters The payment parameters to include in the payment request.
231
+ # @return [String] An HTML snippet that can be included in a form that POSTs to the
232
+ # Adyen payment system.
101
233
  def self.hidden_fields(parameters = {})
102
- # Generate hidden input tags
234
+
235
+ # Generate a hidden input tag per parameter, join them by newlines.
103
236
  payment_parameters(parameters).map { |key, value|
104
237
  self.tag(:input, :type => 'hidden', :name => key.to_s.camelize(:lower), :value => value)
105
238
  }.join("\n")
@@ -109,6 +242,10 @@ module Adyen
109
242
  # MERCHANT SIGNATURE CALCULATION
110
243
  ######################################################
111
244
 
245
+ # Generates the string that is used to calculate the request signature. This signature
246
+ # is used by Adyen to check whether the request is genuinely originating from you.
247
+ # @param [Hash] parameters The parameters that will be included in the payment request.
248
+ # @return [String] The string for which the siganture is calculated.
112
249
  def self.calculate_signature_string(parameters)
113
250
  merchant_sig_string = ""
114
251
  merchant_sig_string << parameters[:payment_amount].to_s << parameters[:currency_code].to_s <<
@@ -120,26 +257,80 @@ module Adyen
120
257
  parameters[:shopper_statement].to_s << parameters[:billing_address_type].to_s
121
258
  end
122
259
 
123
- def self.calculate_signature(parameters)
124
- Adyen::Encoding.hmac_base64(parameters.delete(:shared_secret), calculate_signature_string(parameters))
260
+ # Calculates the payment request signature for the given payment parameters.
261
+ #
262
+ # This signature is used by Adyen to check whether the request is
263
+ # genuinely originating from you. The resulting signature should be
264
+ # included in the payment request parameters as the +merchantSig+
265
+ # parameter; the shared secret should of course not be included.
266
+ #
267
+ # @param [Hash] parameters The payment parameters for which to calculate
268
+ # the payment request signature.
269
+ # @param [String] shared_secret The shared secret to use for this signature.
270
+ # It should correspond with the skin_code parameter. This parameter can be
271
+ # left out if the shared_secret is included as key in the parameters.
272
+ # @return [String] The signature of the payment request
273
+ def self.calculate_signature(parameters, shared_secret = nil)
274
+ shared_secret ||= parameters.delete(:shared_secret)
275
+ Adyen::Encoding.hmac_base64(shared_secret, calculate_signature_string(parameters))
125
276
  end
126
277
 
127
278
  ######################################################
128
279
  # REDIRECT SIGNATURE CHECKING
129
280
  ######################################################
130
281
 
282
+ # Generates the string for which the redirect signature is calculated, using the request paramaters.
283
+ # @param [Hash] params A hash of HTTP GET parameters for the redirect request.
284
+ # @return [String] The signature string.
131
285
  def self.redirect_signature_string(params)
132
286
  params[:authResult].to_s + params[:pspReference].to_s + params[:merchantReference].to_s + params[:skinCode].to_s
133
287
  end
134
-
288
+
289
+ # Computes the redirect signature using the request parameters, so that the
290
+ # redirect can be checked for forgery.
291
+ #
292
+ # @param [Hash] params A hash of HTTP GET parameters for the redirect request.
293
+ # @param [String] shared_secret The shared secret for the Adyen skin that was used for
294
+ # the original payment form. You can leave this out of the skin is registered
295
+ # using the {Adyen::Form.register_skin} method.
296
+ # @return [String] The redirect signature
135
297
  def self.redirect_signature(params, shared_secret = nil)
136
298
  shared_secret ||= lookup_shared_secret(params[:skinCode])
137
299
  Adyen::Encoding.hmac_base64(shared_secret, redirect_signature_string(params))
138
300
  end
139
301
 
302
+ # Checks the redirect signature for this request by calcultating the signature from
303
+ # the provided parameters, and comparing it to the signature provided in the +merchantSig+
304
+ # parameter.
305
+ #
306
+ # If this method returns false, the request could be a forgery and should not be handled.
307
+ # Therefore, you should include this check in a +before_filter+, and raise an error of the
308
+ # signature check fails.
309
+ #
310
+ # @example
311
+ # class PaymentsController < ApplicationController
312
+ # before_filter :check_signature, :only => [:return_from_adyen]
313
+ #
314
+ # def return_from_adyen
315
+ # @invoice = Invoice.find(params[:merchantReference])
316
+ # @invoice.set_paid! if params[:authResult] == 'AUTHORISED'
317
+ # end
318
+ #
319
+ # private
320
+ #
321
+ # def check_signature
322
+ # raise "Forgery!" unless Adyen::Form.redirect_signature_check(params)
323
+ # end
324
+ # end
325
+ #
326
+ # @param [Hash] params params A hash of HTTP GET parameters for the redirect request. This
327
+ # should include the +:merchantSig+ parameter, which contains the signature.
328
+ # @param [String] shared_secret The shared secret for the Adyen skin that was used for
329
+ # the original payment form. You can leave this out of the skin is registered
330
+ # using the {Adyen::Form.register_skin} method.
331
+ # @return [true, false] Returns true only if the signature in the parameters is correct.
140
332
  def self.redirect_signature_check(params, shared_secret = nil)
141
333
  params[:merchantSig] == redirect_signature(params, shared_secret)
142
334
  end
143
-
144
335
  end
145
- end
336
+ end
@@ -1,18 +1,51 @@
1
1
  require 'activerecord'
2
2
 
3
3
  module Adyen
4
+
5
+ # The +Adyen::Notification+ class handles notifications sent by Adyen to your servers.
6
+ #
7
+ # Because notifications contain important payment status information, you should store
8
+ # these notifications in your database. For this reason, +Adyen::Notification+ inherits
9
+ # from +ActiveRecord::Base+, and a migration is included to simply create a suitable table
10
+ # to store the notifications in.
11
+ #
12
+ # Adyen can either send notifications to you via HTTP POST requests, or SOAP requests.
13
+ # Because SOAP is not really well supported in Rails and setting up a SOAP server is
14
+ # not trivial, only handling HTTP POST notifications is currently supported.
15
+ #
16
+ # @example
17
+ # @notification = Adyen::Notification::HttpPost.log(request)
18
+ # if @notification.successful_authorisation?
19
+ # @invoice = Invoice.find(@notification.merchant_reference)
20
+ # @invoice.set_paid!
21
+ # end
22
+ #
23
+ # @see Adyen::Notification::HttpPost.log
4
24
  class Notification < ActiveRecord::Base
5
25
 
26
+ # The default table name to use for the notifications table.
6
27
  DEFAULT_TABLE_NAME = :adyen_notifications
7
28
  set_table_name(DEFAULT_TABLE_NAME)
8
29
 
30
+ # A notification should always include an event_code
9
31
  validates_presence_of :event_code
32
+
33
+ # A notification should always include a psp_reference
10
34
  validates_presence_of :psp_reference
35
+
36
+ # A notification should be unique using the composed key of
37
+ # [:psp_reference, :event_code, :success]
11
38
  validates_uniqueness_of :success, :scope => [:psp_reference, :event_code]
12
39
 
13
40
  # Make sure we don't end up with an original_reference with an empty string
14
41
  before_validation { |notification| notification.original_reference = nil if notification.original_reference.blank? }
15
42
 
43
+ # Logs an incoming notification into the database.
44
+ #
45
+ # @param [Hash] params The notification parameters that should be stored in the database.
46
+ # @return [Adyen::Notification] The initiated and persisted notification instance.
47
+ # @raise This method will raise an exception if the notification cannot be stored.
48
+ # @see Adyen::Notification::HttpPost.log
16
49
  def self.log(params)
17
50
  converted_params = {}
18
51
  # Convert each attribute from CamelCase notation to under_score notation
@@ -24,16 +57,30 @@ module Adyen
24
57
  self.create!(converted_params)
25
58
  end
26
59
 
60
+ # Returns true if this notification is an AUTHORISATION notification
61
+ # @return [true, false] true iff event_code == 'AUTHORISATION'
62
+ # @see Adyen.notification#successful_authorisation?
27
63
  def authorisation?
28
64
  event_code == 'AUTHORISATION'
29
65
  end
30
66
 
31
67
  alias :authorization? :authorisation?
32
68
 
69
+ # Returns true if this notification is an AUTHORISATION notification and
70
+ # the success status indicates that the authorization was successfull.
71
+ # @return [true, false] true iff the notification is an authorization
72
+ # and the authorization was successful according to the success field.
33
73
  def successful_authorisation?
34
74
  event_code == 'AUTHORISATION' && success?
35
75
  end
76
+
77
+ alias :successful_authorization? :successful_authorisation?
36
78
 
79
+ # Collect a payment using the recurring contract that was initiated with
80
+ # this notification. The payment is collected using a SOAP call to the
81
+ # Adyen SOAP service for recurring payments.
82
+ # @param [Hash] options The payment parameters.
83
+ # @see Adyen::SOAP::RecurringService#submit
37
84
  def collect_payment_for_recurring_contract!(options)
38
85
  # Make sure we convert the value to cents
39
86
  options[:value] = Adyen::Formatter::Price.in_cents(options[:value])
@@ -41,13 +88,16 @@ module Adyen
41
88
  Adyen::SOAP::RecurringService.submit(options.merge(:recurring_reference => self.psp_reference))
42
89
  end
43
90
 
91
+ # Deactivates the recurring contract that was initiated with this notification.
92
+ # The contract is deactivated by sending a SOAP call to the Adyen SOAP service for
93
+ # recurring contracts.
94
+ # @param [Hash] options The recurring contract parameters.
95
+ # @see Adyen::SOAP::RecurringService#deactivate
44
96
  def deactivate_recurring_contract!(options)
45
97
  raise "This is not a recurring contract!" unless event_code == 'RECURRING_CONTRACT'
46
98
  Adyen::SOAP::RecurringService.deactivate(options.merge(:recurring_reference => self.psp_reference))
47
99
  end
48
100
 
49
- alias :successful_authorization? :successful_authorisation?
50
-
51
101
  class HttpPost < Notification
52
102
 
53
103
  def self.log(request)
@@ -67,6 +117,8 @@ module Adyen
67
117
  end
68
118
  end
69
119
 
120
+ # An ActiveRecord migration that can be used to create a suitable table
121
+ # to store Adyen::Notification instances for your application.
70
122
  class Migration < ActiveRecord::Migration
71
123
 
72
124
  def self.up(table_name = Adyen::Notification::DEFAULT_TABLE_NAME)
@@ -47,19 +47,18 @@ module Adyen
47
47
  klass.endpoint :version => 1, :uri => 'bogus'
48
48
  end
49
49
 
50
- # Setup basic auth headers in the HTTP client
50
+ # Setup some CURL options to handle redirects correctly.
51
51
  def on_after_create_http_client(http_client)
52
- debug { |logger| logger.puts "Authorization: #{Adyen::SOAP.username}:#{Adyen::SOAP.password}..." }
53
- # Handsoap BUG: Setting headers does not work, using a Curb specific method for now.
54
- # auth = Base64.encode64("#{Adyen::SOAP.username}:#{Adyen::SOAP.password}").chomp
55
- # http_client.headers['Authorization'] = "Basic #{auth}"
56
- http_client.userpwd = "#{Adyen::SOAP.username}:#{Adyen::SOAP.password}"
57
-
58
- # Setup some CURL options to handle redirects correctly.
59
52
  http_client.follow_location = true
60
53
  http_client.max_redirects = 1
61
54
  end
62
55
 
56
+ # Setup basic authentication
57
+ def on_after_create_http_request(http_request)
58
+ debug { |logger| logger.puts "Authorization: #{Adyen::SOAP.username}:#{Adyen::SOAP.password}..." }
59
+ http_request.set_auth Adyen::SOAP.username, Adyen::SOAP.password
60
+ end
61
+
63
62
  # Setup XML namespaces for SOAP request body
64
63
  def on_create_document(doc)
65
64
  doc.alias 'payment', 'http://payment.services.adyen.com'
@@ -128,6 +127,22 @@ module Adyen
128
127
  end
129
128
  end
130
129
 
130
+ # Retrieves the recurring contracts for a shopper. Requires the following arguments:
131
+ #
132
+ # * <tt>:merchent_account</tt> The merchant account under which to place
133
+ # this payment.
134
+ # * <tt>:shopper_reference</tt> The refrence of the shopper. This should be
135
+ # the same as the reference that was used to create the recurring contract.
136
+ def list(args = {})
137
+ invoke_args = Adyen::SOAP.default_arguments.merge(args)
138
+ response = invoke('recurring:listRecurringDetails') do |message|
139
+ message.add('recurring:recurringRequest') do |req|
140
+ req.add('recurring:merchantAccount', invoke_args[:merchant_account])
141
+ req.add('recurring:shopperReference', invoke_args[:shopper_reference])
142
+ end
143
+ end
144
+ end
145
+
131
146
  # Deactivates a recurring payment contract. Requires the following arguments:
132
147
  #
133
148
  # * <tt>:merchent_account</tt> The merchant account under which to place
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adyen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willem van Bergen
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-12-11 00:00:00 +01:00
13
+ date: 2009-12-14 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency