wvanbergen-adyen 0.1.1 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +4 -4
- data/README.rdoc +16 -9
- data/Rakefile +1 -1
- data/adyen.gemspec +22 -13
- data/lib/adyen.rb +5 -5
- data/lib/adyen/form.rb +26 -20
- data/lib/adyen/formatter.rb +1 -1
- data/lib/adyen/matchers.rb +22 -22
- data/lib/adyen/notification.rb +23 -25
- data/lib/adyen/soap.rb +33 -33
- data/spec/adyen_spec.rb +9 -9
- data/spec/form_spec.rb +64 -40
- data/spec/notification_spec.rb +27 -27
- data/tasks/github-gem.rake +124 -74
- metadata +14 -11
data/LICENSE
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
Copyright (c) 2008 Willem van Bergen and Michel Barbosa
|
2
|
-
|
1
|
+
Copyright (c) 2008 - 2009 Willem van Bergen and Michel Barbosa
|
2
|
+
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
a copy of this software and associated documentation files (the
|
5
5
|
"Software"), to deal in the Software without restriction, including
|
@@ -7,10 +7,10 @@ without limitation the rights to use, copy, modify, merge, publish,
|
|
7
7
|
distribute, sublicense, and/or sell copies of the Software, and to
|
8
8
|
permit persons to whom the Software is furnished to do so, subject to
|
9
9
|
the following conditions:
|
10
|
-
|
10
|
+
|
11
11
|
The above copyright notice and this permission notice shall be
|
12
12
|
included in all copies or substantial portions of the Software.
|
13
|
-
|
13
|
+
|
14
14
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
15
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
16
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
data/README.rdoc
CHANGED
@@ -2,20 +2,27 @@
|
|
2
2
|
|
3
3
|
Package to simplify including the Adyen payments services into a Ruby on Rails application.
|
4
4
|
|
5
|
-
Adyen integration relies on three modes of communication between Adyen, your server and
|
5
|
+
Adyen integration relies on three modes of communication between Adyen, your server and
|
6
|
+
your client/customer:
|
6
7
|
|
7
8
|
* Client-to-Adyen communication using forms and redirects.
|
8
9
|
* Adyen-to-server communications using notifications.
|
9
10
|
* Server-to-Adyen communication using SOAP services.
|
10
11
|
|
11
|
-
This library aims to ease the implementation of all these modes into your application.
|
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.
|
12
15
|
|
13
16
|
== Installation
|
14
17
|
|
15
|
-
|
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:
|
16
20
|
|
17
|
-
gem
|
18
|
-
|
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
|
19
26
|
|
20
27
|
== Usage
|
21
28
|
|
@@ -23,10 +30,10 @@ See the project wiki on http://wiki.github.com/wvanbergen/adyen to get started.
|
|
23
30
|
|
24
31
|
* For more information about Adyen, see http://www.adyen.com
|
25
32
|
* For more information about integrating Adyen, see their manuals at
|
26
|
-
http://support.adyen.com/links/documentation
|
33
|
+
http://support.adyen.com/links/documentation
|
27
34
|
|
28
35
|
== About
|
29
36
|
|
30
|
-
This package is written by Michel Barbosa and Willem van Bergen for Floorplanner.com,
|
31
|
-
|
32
|
-
|
37
|
+
This package is written by Michel Barbosa and Willem van Bergen for Floorplanner.com, and
|
38
|
+
made public under the MIT license (see LICENSE). It comes without warranty of any kind, so
|
39
|
+
use at your own risk.
|
data/Rakefile
CHANGED
data/adyen.gemspec
CHANGED
@@ -1,21 +1,30 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
|
-
s.name = 'adyen'
|
3
|
-
s.version = "0.1.
|
4
|
-
s.date = "2009-
|
5
|
-
|
6
|
-
s.summary = "Integrate Adyen payment services in you Ruby on Rails application"
|
7
|
-
s.description =
|
8
|
-
|
2
|
+
s.name = 'wvanbergen-adyen'
|
3
|
+
s.version = "0.1.5"
|
4
|
+
s.date = "2009-10-07"
|
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
|
+
|
9
14
|
s.authors = ['Willem van Bergen', 'Michel Barbosa']
|
10
15
|
s.email = ['willem@vanbergen.org', 'cicaboo@gmail.com']
|
11
|
-
s.homepage = 'http://
|
12
|
-
|
16
|
+
s.homepage = 'http://wiki.github.com/wvanbergen/adyen'
|
17
|
+
|
13
18
|
s.add_development_dependency('rspec', '>= 1.1.4')
|
14
|
-
s.add_development_dependency('git', '>= 1.1.0')
|
15
|
-
|
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
|
+
|
16
25
|
s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
|
17
26
|
s.extra_rdoc_files = ['README.rdoc']
|
18
|
-
|
27
|
+
|
19
28
|
s.files = %w(spec/spec_helper.rb lib/adyen/form.rb .gitignore LICENSE spec/soap_spec.rb spec/notification_spec.rb lib/adyen/soap.rb init.rb spec/adyen_spec.rb adyen.gemspec Rakefile tasks/github-gem.rake spec/form_spec.rb README.rdoc lib/adyen/notification.rb lib/adyen/matchers.rb lib/adyen/formatter.rb lib/adyen.rb lib/adyen/encoding.rb)
|
20
29
|
s.test_files = %w(spec/soap_spec.rb spec/notification_spec.rb spec/adyen_spec.rb spec/form_spec.rb)
|
21
|
-
end
|
30
|
+
end
|
data/lib/adyen.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
module Adyen
|
2
|
-
LIVE_RAILS_ENVIRONMENTS = ['production']
|
2
|
+
LIVE_RAILS_ENVIRONMENTS = ['production']
|
3
3
|
|
4
|
-
# Setter voor the current Adyen environment.
|
4
|
+
# Setter voor the current Adyen environment.
|
5
5
|
# Must be either 'test' or 'live'
|
6
6
|
def self.environment=(env)
|
7
7
|
@environment = env
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
# Returns the current Adyen environment.
|
11
11
|
# Returns either 'test' or 'live'.
|
12
12
|
def self.environment(override = nil)
|
13
13
|
override || @environment || Adyen.autodetect_environment
|
14
|
-
end
|
14
|
+
end
|
15
15
|
|
16
16
|
# Autodetects the Adyen environment based on the RAILS_ENV constant
|
17
17
|
def self.autodetect_environment
|
18
18
|
(defined?(RAILS_ENV) && Adyen::LIVE_RAILS_ENVIRONMENTS.include?(RAILS_ENV.to_s.downcase)) ? 'live' : 'test'
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
# Loads submodules on demand, so that dependencies are not required.
|
22
22
|
def self.const_missing(sym)
|
23
23
|
require "adyen/#{sym.to_s.downcase}"
|
data/lib/adyen/form.rb
CHANGED
@@ -2,70 +2,76 @@ require 'action_view'
|
|
2
2
|
|
3
3
|
module Adyen
|
4
4
|
module Form
|
5
|
-
|
5
|
+
|
6
6
|
extend ActionView::Helpers::TagHelper
|
7
|
-
|
7
|
+
|
8
8
|
ACTION_URL = "https://%s.adyen.com/hpp/select.shtml"
|
9
9
|
|
10
10
|
def self.url(environment = nil)
|
11
11
|
environment ||= Adyen.environment(environment)
|
12
12
|
Adyen::Form::ACTION_URL % environment.to_s
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def self.calculate_signature_string(attributes)
|
16
16
|
merchant_sig_string = ""
|
17
|
-
merchant_sig_string << attributes[:payment_amount].to_s << attributes[:currency_code].to_s <<
|
18
|
-
attributes[:ship_before_date].to_s << attributes[:merchant_reference].to_s <<
|
17
|
+
merchant_sig_string << attributes[:payment_amount].to_s << attributes[:currency_code].to_s <<
|
18
|
+
attributes[:ship_before_date].to_s << attributes[:merchant_reference].to_s <<
|
19
19
|
attributes[:skin_code].to_s << attributes[:merchant_account].to_s <<
|
20
20
|
attributes[:session_validity].to_s << attributes[:shopper_email].to_s <<
|
21
21
|
attributes[:shopper_reference].to_s << attributes[:recurring_contract].to_s <<
|
22
22
|
attributes[:allowed_methods].to_s << attributes[:blocked_methods].to_s <<
|
23
23
|
attributes[:shopper_statement].to_s << attributes[:billing_address_type].to_s
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def self.calculate_signature(attributes)
|
27
27
|
Adyen::Encoding.hmac_base64(attributes.delete(:shared_secret), calculate_signature_string(attributes))
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def self.do_attribute_transformations!(attributes = {})
|
31
31
|
raise "YENs are not yet supported!" if attributes[:currency_code] == 'JPY' # TODO: fixme
|
32
|
-
|
32
|
+
|
33
33
|
attributes[:recurring_contract] = 'DEFAULT' if attributes.delete(:recurring) == true
|
34
34
|
attributes[:order_data] = Adyen::Encoding.gzip_base64(attributes.delete(:order_data_raw)) if attributes[:order_data_raw]
|
35
35
|
attributes[:ship_before_date] = Adyen::Formatter::DateTime.fmt_date(attributes[:ship_before_date])
|
36
36
|
attributes[:session_validity] = Adyen::Formatter::DateTime.fmt_time(attributes[:session_validity])
|
37
37
|
end
|
38
|
-
|
39
38
|
|
40
|
-
def self.
|
39
|
+
def self.payment_fields(attributes = {})
|
41
40
|
do_attribute_transformations!(attributes)
|
42
|
-
|
41
|
+
|
43
42
|
raise "Cannot generate form: :currency code attribute not found!" unless attributes[:currency_code]
|
44
|
-
raise "Cannot generate form: :payment_amount code attribute not found!" unless attributes[:payment_amount]
|
43
|
+
raise "Cannot generate form: :payment_amount code attribute not found!" unless attributes[:payment_amount]
|
45
44
|
raise "Cannot generate form: :merchant_account attribute not found!" unless attributes[:merchant_account]
|
46
45
|
raise "Cannot generate form: :skin_code attribute not found!" unless attributes[:skin_code]
|
47
46
|
raise "Cannot generate form: :shared_secret signing secret not provided!" unless attributes[:shared_secret]
|
48
|
-
|
47
|
+
|
49
48
|
# Merchant signature
|
50
49
|
attributes[:merchant_sig] = calculate_signature(attributes)
|
51
|
-
|
50
|
+
return attributes
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.redirect_url(attributes)
|
54
|
+
self.url + '?' + payment_fields(attributes).map { |(k, v)| "#{k.to_s.camelize(:lower)}=#{CGI.escape(v.to_s)}" }.join('&')
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.hidden_fields(attributes = {})
|
52
58
|
# Generate hidden input tags
|
53
|
-
attributes.map { |key, value|
|
59
|
+
payment_fields(attributes).map { |key, value|
|
54
60
|
self.tag(:input, :type => 'hidden', :name => key.to_s.camelize(:lower), :value => value)
|
55
61
|
}.join("\n")
|
56
62
|
end
|
57
|
-
|
63
|
+
|
58
64
|
def self.redirect_signature_string(params)
|
59
65
|
params[:authResult].to_s + params[:pspReference].to_s + params[:merchantReference].to_s + params[:skinCode].to_s
|
60
66
|
end
|
61
|
-
|
67
|
+
|
62
68
|
def self.redirect_signature(params, shared_secret)
|
63
69
|
Adyen::Encoding.hmac_base64(shared_secret, redirect_signature_string(params))
|
64
70
|
end
|
65
|
-
|
71
|
+
|
66
72
|
def self.redirect_signature_check(params, shared_secret)
|
67
73
|
params[:merchantSig] == redirect_signature(params, shared_secret)
|
68
|
-
end
|
69
|
-
|
74
|
+
end
|
75
|
+
|
70
76
|
end
|
71
77
|
end
|
data/lib/adyen/formatter.rb
CHANGED
data/lib/adyen/matchers.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
require 'xml'
|
2
2
|
|
3
3
|
module Adyen
|
4
|
-
module Matchers
|
5
|
-
|
4
|
+
module Matchers
|
5
|
+
|
6
6
|
module XPathPaymentFormCheck
|
7
|
-
|
7
|
+
|
8
8
|
def self.build_xpath_query(checks)
|
9
9
|
# Start by finding the check for the Adyen form tag
|
10
|
-
xpath_query = "//form[@action='#{Adyen::Form.url}']"
|
10
|
+
xpath_query = "//form[@action='#{Adyen::Form.url}']"
|
11
11
|
|
12
12
|
# Add recurring/single check if specified
|
13
13
|
recurring = checks.delete(:recurring)
|
14
14
|
unless recurring.nil?
|
15
15
|
if recurring
|
16
|
-
xpath_query << "[descendant::input[@type='hidden'][@name='recurringContract']]"
|
16
|
+
xpath_query << "[descendant::input[@type='hidden'][@name='recurringContract']]"
|
17
17
|
else
|
18
18
|
xpath_query << "[not(descendant::input[@type='hidden'][@name='recurringContract'])]"
|
19
19
|
end
|
@@ -24,9 +24,9 @@ module Adyen
|
|
24
24
|
condition = "descendant::input[@type='hidden'][@name='#{key.to_s.camelize(:lower)}']"
|
25
25
|
condition << "[@value='#{value}']" unless value == :anything
|
26
26
|
xpath_query << "[#{condition}]"
|
27
|
-
end
|
27
|
+
end
|
28
28
|
|
29
|
-
return xpath_query
|
29
|
+
return xpath_query
|
30
30
|
end
|
31
31
|
|
32
32
|
def self.document(subject)
|
@@ -45,27 +45,27 @@ module Adyen
|
|
45
45
|
|
46
46
|
def self.check(subject, checks = {})
|
47
47
|
document(subject).find_first(build_xpath_query(checks))
|
48
|
-
end
|
48
|
+
end
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
class HaveAdyenPaymentForm
|
52
|
-
|
52
|
+
|
53
53
|
def initialize(checks)
|
54
54
|
@checks = checks
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def matches?(document)
|
58
58
|
Adyen::Matchers::XPathPaymentFormCheck.check(document, @checks)
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
def description
|
62
62
|
"have an adyen payment form"
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
def failure_message
|
66
66
|
"expected to find a valid Adyen form on this page"
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
def negative_failure_message
|
70
70
|
"expected not to find a valid Adyen form on this page"
|
71
71
|
end
|
@@ -75,31 +75,31 @@ module Adyen
|
|
75
75
|
default_checks = {:merchant_sig => :anything, :payment_amount => :anything, :currency_code => :anything, :skin_code => :anything }
|
76
76
|
HaveAdyenPaymentForm.new(default_checks.merge(checks))
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
def have_adyen_recurring_payment_form(checks = {})
|
80
80
|
recurring_checks = { :recurring => true, :shopper_email => :anything, :shopper_reference => :anything }
|
81
81
|
have_adyen_payment_form(recurring_checks.merge(checks))
|
82
|
-
end
|
83
|
-
|
82
|
+
end
|
83
|
+
|
84
84
|
def have_adyen_single_payment_form(checks = {})
|
85
85
|
recurring_checks = { :recurring => false }
|
86
86
|
have_adyen_payment_form(recurring_checks.merge(checks))
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
def assert_adyen_payment_form(subject, checks = {})
|
90
90
|
default_checks = {:merchant_sig => :anything, :payment_amount => :anything, :currency_code => :anything, :skin_code => :anything }
|
91
91
|
assert Adyen::Matchers::XPathPaymentFormCheck.check(subject, default_checks.merge(checks)), 'No Adyen payment form found'
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
def assert_adyen_recurring_payment_form(subject, checks = {})
|
95
95
|
recurring_checks = { :recurring => true, :shopper_email => :anything, :shopper_reference => :anything }
|
96
96
|
assert_adyen_payment_form(subject, recurring_checks.merge(checks))
|
97
|
-
end
|
97
|
+
end
|
98
98
|
|
99
99
|
def assert_adyen_single_payment_form(subject, checks = {})
|
100
100
|
recurring_checks = { :recurring => false }
|
101
101
|
assert_adyen_payment_form(subject, recurring_checks.merge(checks))
|
102
|
-
end
|
103
|
-
|
102
|
+
end
|
103
|
+
|
104
104
|
end
|
105
105
|
end
|
data/lib/adyen/notification.rb
CHANGED
@@ -2,14 +2,14 @@ require 'activerecord'
|
|
2
2
|
|
3
3
|
module Adyen
|
4
4
|
class Notification < ActiveRecord::Base
|
5
|
-
|
5
|
+
|
6
6
|
DEFAULT_TABLE_NAME = :adyen_notifications
|
7
7
|
set_table_name(DEFAULT_TABLE_NAME)
|
8
|
-
|
8
|
+
|
9
9
|
validates_presence_of :event_code
|
10
|
-
validates_presence_of :psp_reference
|
10
|
+
validates_presence_of :psp_reference
|
11
11
|
validates_uniqueness_of :success, :scope => [:psp_reference, :event_code]
|
12
|
-
|
12
|
+
|
13
13
|
# Make sure we don't end up with an original_reference with an empty string
|
14
14
|
before_validation { |notification| notification.original_reference = nil if notification.original_reference.blank? }
|
15
15
|
|
@@ -17,37 +17,37 @@ module Adyen
|
|
17
17
|
converted_params = {}
|
18
18
|
# Convert each attribute from CamelCase notation to under_score notation
|
19
19
|
# For example, merchantReference will be converted to merchant_reference
|
20
|
-
params.each do |key, value|
|
20
|
+
params.each do |key, value|
|
21
21
|
field_name = key.to_s.underscore
|
22
22
|
converted_params[field_name] = value if self.column_names.include?(field_name)
|
23
23
|
end
|
24
24
|
self.create!(converted_params)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def authorisation?
|
28
28
|
event_code == 'AUTHORISATION'
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
alias :authorization? :authorisation?
|
32
|
-
|
32
|
+
|
33
33
|
def successful_authorisation?
|
34
34
|
event_code == 'AUTHORISATION' && success?
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def collect_payment_for_recurring_contract!(options)
|
38
38
|
# Make sure we convert the value to cents
|
39
39
|
options[:value] = Adyen::Formatter::Price.in_cents(options[:value])
|
40
40
|
raise "This is not a recurring contract!" unless event_code == 'RECURRING_CONTRACT'
|
41
41
|
Adyen::SOAP::RecurringService.submit(options.merge(:recurring_reference => self.psp_reference))
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
def deactivate_recurring_contract!(options)
|
45
|
-
raise "This is not a recurring contract!" unless event_code == 'RECURRING_CONTRACT'
|
45
|
+
raise "This is not a recurring contract!" unless event_code == 'RECURRING_CONTRACT'
|
46
46
|
Adyen::SOAP::RecurringService.deactivate(options.merge(:recurring_reference => self.psp_reference))
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
alias :successful_authorization? :successful_authorisation?
|
50
|
-
|
50
|
+
|
51
51
|
class HttpPost < Notification
|
52
52
|
|
53
53
|
def self.log(request)
|
@@ -55,22 +55,22 @@ module Adyen
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def live=(value)
|
58
|
-
self.write_attribute(:live, [true, 1, '1', 'true'].include?(value))
|
58
|
+
self.write_attribute(:live, [true, 1, '1', 'true'].include?(value))
|
59
59
|
end
|
60
60
|
|
61
61
|
def success=(value)
|
62
|
-
self.write_attribute(:success, [true, 1, '1', 'true'].include?(value))
|
63
|
-
end
|
64
|
-
|
62
|
+
self.write_attribute(:success, [true, 1, '1', 'true'].include?(value))
|
63
|
+
end
|
64
|
+
|
65
65
|
def value=(value)
|
66
66
|
self.write_attribute(:value, Adyen::Formatter::Price.from_cents(value)) unless value.blank?
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
class Migration < ActiveRecord::Migration
|
71
|
-
|
71
|
+
|
72
72
|
def self.up(table_name = Adyen::Notification::DEFAULT_TABLE_NAME)
|
73
|
-
create_table(table_name) do |t|
|
73
|
+
create_table(table_name) do |t|
|
74
74
|
t.boolean :live, :null => false, :default => false
|
75
75
|
t.string :event_code, :null => false
|
76
76
|
t.string :psp_reference, :null => false
|
@@ -87,15 +87,13 @@ module Adyen
|
|
87
87
|
t.boolean :processed, :null => false, :default => false
|
88
88
|
t.timestamps
|
89
89
|
end
|
90
|
-
add_index table_name, [:psp_reference, :event_code, :success], :unique => true
|
90
|
+
add_index table_name, [:psp_reference, :event_code, :success], :unique => true, :name => 'adyen_notification_uniqueness'
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
def self.down(table_name = Adyen::Notification::DEFAULT_TABLE_NAME)
|
94
|
-
remove_index(table_name,
|
94
|
+
remove_index(table_name, :name => 'adyen_notification_uniqueness')
|
95
95
|
drop_table(table_name)
|
96
96
|
end
|
97
|
-
|
98
97
|
end
|
99
|
-
|
100
98
|
end
|
101
99
|
end
|