activemerchant 1.14.0 → 1.15.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +18 -0
- data/CONTRIBUTORS +4 -0
- data/README.rdoc +1 -0
- data/lib/active_merchant.rb +1 -1
- data/lib/active_merchant/billing/credit_card.rb +53 -42
- data/lib/active_merchant/billing/gateway.rb +6 -6
- data/lib/active_merchant/billing/gateways/authorize_net.rb +4 -2
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +1 -1
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +3 -3
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +1 -1
- data/lib/active_merchant/billing/gateways/bogus.rb +12 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +77 -16
- data/lib/active_merchant/billing/gateways/eway.rb +0 -4
- data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +1 -1
- data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +1 -1
- data/lib/active_merchant/billing/gateways/orbital.rb +1 -1
- data/lib/active_merchant/billing/gateways/pay_junction.rb +1 -1
- data/lib/active_merchant/billing/gateways/payflow.rb +22 -8
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +10 -10
- data/lib/active_merchant/billing/gateways/payflow_express.rb +115 -36
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
- data/lib/active_merchant/billing/gateways/qbms.rb +1 -1
- data/lib/active_merchant/billing/gateways/realex.rb +7 -20
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +5 -5
- data/lib/active_merchant/billing/gateways/viaklix.rb +1 -1
- data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +18 -10
- data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
- data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
- data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
- data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
- data/lib/active_merchant/billing/integrations/helper.rb +4 -4
- data/lib/active_merchant/billing/integrations/notification.rb +1 -1
- data/lib/active_merchant/common/post_data.rb +1 -1
- data/lib/active_merchant/common/posts_data.rb +1 -1
- data/lib/active_merchant/common/validateable.rb +20 -15
- data/lib/active_merchant/version.rb +1 -1
- metadata +20 -21
- metadata.gz.sig +0 -0
@@ -17,7 +17,7 @@ module ActiveMerchant #:nodoc:
|
|
17
17
|
# The name of the gateway
|
18
18
|
self.display_name = 'SecurePay'
|
19
19
|
|
20
|
-
|
20
|
+
class_attribute :request_timeout
|
21
21
|
self.request_timeout = 60
|
22
22
|
|
23
23
|
self.money_format = :cents
|
@@ -58,20 +58,20 @@ module ActiveMerchant #:nodoc:
|
|
58
58
|
commit :authorization, build_purchase_request(money, credit_card, options)
|
59
59
|
end
|
60
60
|
|
61
|
-
def capture(money, reference)
|
61
|
+
def capture(money, reference, options = {})
|
62
62
|
commit :capture, build_reference_request(money, reference)
|
63
63
|
end
|
64
64
|
|
65
|
-
def refund(money, reference)
|
65
|
+
def refund(money, reference, options = {})
|
66
66
|
commit :refund, build_reference_request(money, reference)
|
67
67
|
end
|
68
68
|
|
69
|
-
def credit(money, reference)
|
69
|
+
def credit(money, reference, options = {})
|
70
70
|
deprecated CREDIT_DEPRECATION_MESSAGE
|
71
71
|
refund(money, reference)
|
72
72
|
end
|
73
73
|
|
74
|
-
def void(reference)
|
74
|
+
def void(reference, options = {})
|
75
75
|
commit :void, build_reference_request(nil, reference)
|
76
76
|
end
|
77
77
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveMerchant #:nodoc:
|
2
2
|
module Billing #:nodoc:
|
3
3
|
class ViaklixGateway < Gateway
|
4
|
-
|
4
|
+
class_attribute :test_url, :live_url, :delimiter, :actions
|
5
5
|
|
6
6
|
self.test_url = 'https://demo.viaklix.com/process.asp'
|
7
7
|
self.live_url = 'https://www.viaklix.com/process.asp'
|
@@ -64,8 +64,7 @@ module ActiveMerchant #:nodoc:
|
|
64
64
|
|
65
65
|
|
66
66
|
def customer(params = {})
|
67
|
-
|
68
|
-
add_field(mappings[:customer][:name], full_name)
|
67
|
+
add_field(mappings[:customer][:name], full_name(params))
|
69
68
|
add_field(mappings[:customer][:email], params[:email])
|
70
69
|
end
|
71
70
|
|
@@ -79,13 +78,11 @@ module ActiveMerchant #:nodoc:
|
|
79
78
|
end
|
80
79
|
|
81
80
|
def shipping_address(params = {})
|
82
|
-
update_address(:shipping_address, params)
|
83
|
-
super(params.dup)
|
81
|
+
super(update_address(:shipping_address, params))
|
84
82
|
end
|
85
83
|
|
86
84
|
def billing_address(params = {})
|
87
|
-
update_address(:billing_address, params)
|
88
|
-
super(params.dup)
|
85
|
+
super(update_address(:billing_address, params))
|
89
86
|
end
|
90
87
|
|
91
88
|
def form_fields
|
@@ -121,15 +118,20 @@ module ActiveMerchant #:nodoc:
|
|
121
118
|
end
|
122
119
|
|
123
120
|
def update_address(address_type, params)
|
121
|
+
params = params.dup
|
124
122
|
address = params[:address1]
|
125
|
-
address
|
126
|
-
params[:
|
123
|
+
address = "#{address} #{params[:address2]}" if params[:address2].present?
|
124
|
+
address = "#{params[:company]} #{address}" if params[:company].present?
|
125
|
+
params[:address1] = address
|
126
|
+
|
127
127
|
params[:phone] = normalize_phone_number(params[:phone])
|
128
128
|
add_land_line_phone_for(address_type, params)
|
129
129
|
|
130
|
-
if address_type == :shipping_address
|
131
|
-
|
130
|
+
if address_type == :shipping_address
|
131
|
+
shipping_name = full_name(params) || fields[mappings[:customer][:name]]
|
132
|
+
add_field(mappings[:shipping_address][:name], shipping_name)
|
132
133
|
end
|
134
|
+
params
|
133
135
|
end
|
134
136
|
|
135
137
|
# Split a single phone number into the country code, area code and local number as best as possible
|
@@ -185,6 +187,12 @@ module ActiveMerchant #:nodoc:
|
|
185
187
|
def phone_code_for_country(country)
|
186
188
|
PHONE_CODES[country]
|
187
189
|
end
|
190
|
+
|
191
|
+
def full_name(params)
|
192
|
+
return if params[:name].blank? && params[:first_name].blank? && params[:last_name].blank?
|
193
|
+
|
194
|
+
params[:name] || "#{params[:first_name]} #{params[:last_name]}"
|
195
|
+
end
|
188
196
|
end
|
189
197
|
end
|
190
198
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module Directebanking
|
5
|
+
autoload :Return, File.dirname(__FILE__) + '/directebanking/return.rb'
|
6
|
+
autoload :Helper, File.dirname(__FILE__) + '/directebanking/helper.rb'
|
7
|
+
autoload :Notification, File.dirname(__FILE__) + '/directebanking/notification.rb'
|
8
|
+
|
9
|
+
# Supported countries:
|
10
|
+
# Germany - DE
|
11
|
+
# Austria - AT
|
12
|
+
# Belgium - BE
|
13
|
+
# Netherlands - NL
|
14
|
+
# Switzerland - CH
|
15
|
+
# Great Britain - GB
|
16
|
+
|
17
|
+
# Overwrite this if you want to change the directebanking test url
|
18
|
+
mattr_accessor :test_url
|
19
|
+
self.test_url = 'https://www.directebanking.com/payment/start'
|
20
|
+
|
21
|
+
# Overwrite this if you want to change the directebanking production url
|
22
|
+
mattr_accessor :production_url
|
23
|
+
self.production_url = 'https://www.directebanking.com/payment/start'
|
24
|
+
|
25
|
+
def self.service_url
|
26
|
+
mode = ActiveMerchant::Billing::Base.integration_mode
|
27
|
+
case mode
|
28
|
+
when :production
|
29
|
+
self.production_url
|
30
|
+
when :test
|
31
|
+
self.test_url
|
32
|
+
else
|
33
|
+
raise StandardError, "Integration mode set to an invalid value: #{mode}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.notification(post, options = {})
|
38
|
+
Notification.new(post, options)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.return(post, options = {})
|
42
|
+
Return.new(post, options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module Directebanking
|
5
|
+
class Helper < ActiveMerchant::Billing::Integrations::Helper
|
6
|
+
|
7
|
+
# All credentials are mandatory and need to be set
|
8
|
+
#
|
9
|
+
# credential1: User ID
|
10
|
+
# credential2: Project ID
|
11
|
+
# credential3: Project Password (Algorithm: SH1)
|
12
|
+
# credential4: Notification Password (Algorithm: SH1)
|
13
|
+
def initialize(order, account, options = {})
|
14
|
+
super
|
15
|
+
add_field('user_variable_0', order)
|
16
|
+
add_field('project_id', options[:credential2])
|
17
|
+
@project_password = options[:credential3]
|
18
|
+
end
|
19
|
+
|
20
|
+
SIGNATURE_FIELDS = [
|
21
|
+
:user_id,
|
22
|
+
:project_id,
|
23
|
+
:sender_holder,
|
24
|
+
:sender_account_number,
|
25
|
+
:sender_bank_code,
|
26
|
+
:sender_country_id,
|
27
|
+
:amount,
|
28
|
+
:currency_id,
|
29
|
+
:reason_1,
|
30
|
+
:reason_2,
|
31
|
+
:user_variable_0,
|
32
|
+
:user_variable_1,
|
33
|
+
:user_variable_2,
|
34
|
+
:user_variable_3,
|
35
|
+
:user_variable_4,
|
36
|
+
:user_variable_5
|
37
|
+
]
|
38
|
+
|
39
|
+
SIGNATURE_IGNORE_AT_METHOD_CREATION_FIELDS = [
|
40
|
+
:user_id,
|
41
|
+
:amount,
|
42
|
+
:project_id,
|
43
|
+
:currency_id,
|
44
|
+
:user_variable_0,
|
45
|
+
:user_variable_1,
|
46
|
+
:user_variable_2,
|
47
|
+
:user_variable_3
|
48
|
+
]
|
49
|
+
|
50
|
+
SIGNATURE_FIELDS.each do |key|
|
51
|
+
if !SIGNATURE_IGNORE_AT_METHOD_CREATION_FIELDS.include?(key)
|
52
|
+
mapping "#{key}".to_sym, "#{key.to_s}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Need to format the amount to have 2 decimal places
|
57
|
+
def amount=(money)
|
58
|
+
cents = money.respond_to?(:cents) ? money.cents : money
|
59
|
+
if money.is_a?(String) or cents.to_i <= 0
|
60
|
+
raise ArgumentError, 'money amount must be either a Money object or a positive integer in cents.'
|
61
|
+
end
|
62
|
+
add_field mappings[:amount], sprintf("%.2f", cents.to_f/100)
|
63
|
+
end
|
64
|
+
|
65
|
+
def generate_signature_string
|
66
|
+
# format of signature: user_id|project_id|sender_holder|sender_account_number|sender_bank_code| sender_country_id|amount|currency_id|reason_1|reason_2|user_variable_0|user_variable_1|user_variable_2|user_variable_3|user_variable_4|user_variable_5|project_password
|
67
|
+
SIGNATURE_FIELDS.map {|key| @fields[key.to_s]} * "|" + "|#{@project_password}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def generate_signature
|
71
|
+
Digest::SHA1.hexdigest(generate_signature_string)
|
72
|
+
end
|
73
|
+
|
74
|
+
def form_fields
|
75
|
+
@fields.merge('hash' => generate_signature)
|
76
|
+
end
|
77
|
+
|
78
|
+
mapping :account, 'user_id'
|
79
|
+
mapping :amount, 'amount'
|
80
|
+
mapping :currency, 'currency_id'
|
81
|
+
mapping :description, 'reason_1'
|
82
|
+
|
83
|
+
mapping :return_url, 'user_variable_1'
|
84
|
+
mapping :cancel_return_url, 'user_variable_2'
|
85
|
+
mapping :notify_url, 'user_variable_3'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module Directebanking
|
5
|
+
class Notification < ActiveMerchant::Billing::Integrations::Notification
|
6
|
+
|
7
|
+
def initialize(data, options)
|
8
|
+
if options[:credential4].nil?
|
9
|
+
raise ArgumentError, "You need to provide the notification password (SH1) as the option :credential4 to verify that the notification originated from Directebanking (Payment Networks AG)"
|
10
|
+
end
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def complete?
|
15
|
+
status == 'Completed'
|
16
|
+
end
|
17
|
+
|
18
|
+
def item_id
|
19
|
+
params['user_variable_0']
|
20
|
+
end
|
21
|
+
|
22
|
+
def transaction_id
|
23
|
+
params['transaction']
|
24
|
+
end
|
25
|
+
|
26
|
+
# When was this payment received by the client.
|
27
|
+
def received_at
|
28
|
+
Time.parse(params['created']) if params['created']
|
29
|
+
end
|
30
|
+
|
31
|
+
# the money amount we received in X.2 decimal.
|
32
|
+
def gross
|
33
|
+
"%.2f" % params['amount'].to_f
|
34
|
+
end
|
35
|
+
|
36
|
+
def status
|
37
|
+
'Completed'
|
38
|
+
end
|
39
|
+
|
40
|
+
def currency
|
41
|
+
params['currency_id']
|
42
|
+
end
|
43
|
+
|
44
|
+
def test?
|
45
|
+
params['sender_bank_name'] == 'Testbank'
|
46
|
+
end
|
47
|
+
|
48
|
+
# for verifying the signature of the URL parameters
|
49
|
+
PAYMENT_HOOK_SIGNATURE_FIELDS = [
|
50
|
+
:transaction,
|
51
|
+
:user_id,
|
52
|
+
:project_id,
|
53
|
+
:sender_holder,
|
54
|
+
:sender_account_number,
|
55
|
+
:sender_bank_code,
|
56
|
+
:sender_bank_name,
|
57
|
+
:sender_bank_bic,
|
58
|
+
:sender_iban,
|
59
|
+
:sender_country_id,
|
60
|
+
:recipient_holder,
|
61
|
+
:recipient_account_number,
|
62
|
+
:recipient_bank_code,
|
63
|
+
:recipient_bank_name,
|
64
|
+
:recipient_bank_bic,
|
65
|
+
:recipient_iban,
|
66
|
+
:recipient_country_id,
|
67
|
+
:international_transaction,
|
68
|
+
:amount,
|
69
|
+
:currency_id,
|
70
|
+
:reason_1,
|
71
|
+
:reason_2,
|
72
|
+
:security_criteria,
|
73
|
+
:user_variable_0,
|
74
|
+
:user_variable_1,
|
75
|
+
:user_variable_2,
|
76
|
+
:user_variable_3,
|
77
|
+
:user_variable_4,
|
78
|
+
:user_variable_5,
|
79
|
+
:created
|
80
|
+
]
|
81
|
+
|
82
|
+
PAYMENT_HOOK_IGNORE_AT_METHOD_CREATION_FIELDS = [
|
83
|
+
:transaction,
|
84
|
+
:amount,
|
85
|
+
:currency_id,
|
86
|
+
:user_variable_0,
|
87
|
+
:user_variable_1,
|
88
|
+
:user_variable_2,
|
89
|
+
:user_variable_3,
|
90
|
+
:created
|
91
|
+
]
|
92
|
+
|
93
|
+
# Provide access to raw fields
|
94
|
+
PAYMENT_HOOK_SIGNATURE_FIELDS.each do |key|
|
95
|
+
if !PAYMENT_HOOK_IGNORE_AT_METHOD_CREATION_FIELDS.include?(key)
|
96
|
+
define_method(key.to_s) do
|
97
|
+
params[key.to_s]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def generate_signature_string
|
103
|
+
#format is: transaction|user_id|project_id|sender_holder|sender_account_number|sender_bank_code|sender_bank_name|sender_bank_bic|sender_iban|sender_country_id|recipient_holder|recipient_account_number|recipient_bank_code|recipient_bank_name|recipient_bank_bic|recipient_iban|recipient_country_id|international_transaction|amount|currency_id|reason_1|reason_2|security_criteria|user_variable_0|user_variable_1|user_variable_2|user_variable_3|user_variable_4|user_variable_5|created|notification_password
|
104
|
+
PAYMENT_HOOK_SIGNATURE_FIELDS.map {|key| params[key.to_s]} * "|" + "|#{@options[:credential4]}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def generate_signature
|
108
|
+
Digest::SHA1.hexdigest(generate_signature_string)
|
109
|
+
end
|
110
|
+
|
111
|
+
def acknowledge
|
112
|
+
# signature_is_valid?
|
113
|
+
generate_signature.to_s == params['hash'].to_s
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -3,14 +3,14 @@ module ActiveMerchant #:nodoc:
|
|
3
3
|
module Integrations #:nodoc:
|
4
4
|
class Helper #:nodoc:
|
5
5
|
attr_reader :fields
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
class_attribute :service_url
|
7
|
+
class_attribute :mappings
|
8
|
+
class_attribute :country_format
|
9
9
|
self.country_format = :alpha2
|
10
10
|
|
11
11
|
# The application making the calls to the gateway
|
12
12
|
# Useful for things like the PayPal build notation (BN) id fields
|
13
|
-
|
13
|
+
class_attribute :application_id
|
14
14
|
self.application_id = 'ActiveMerchant'
|
15
15
|
|
16
16
|
def initialize(order, account, options = {})
|
@@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc:
|
|
6
6
|
attr_accessor :raw
|
7
7
|
|
8
8
|
# set this to an array in the subclass, to specify which IPs are allowed to send requests
|
9
|
-
|
9
|
+
class_attribute :production_ips
|
10
10
|
|
11
11
|
def initialize(post, options = {})
|
12
12
|
@options = options
|
@@ -5,7 +5,7 @@ module ActiveMerchant #:nodoc:
|
|
5
5
|
base.superclass_delegating_accessor :ssl_strict
|
6
6
|
base.ssl_strict = true
|
7
7
|
|
8
|
-
base.
|
8
|
+
base.class_attribute :retry_safe
|
9
9
|
base.retry_safe = false
|
10
10
|
|
11
11
|
base.superclass_delegating_accessor :open_timeout
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module ActiveMerchant #:nodoc:
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
2
|
module Validateable #:nodoc:
|
3
3
|
def valid?
|
4
4
|
errors.clear
|
@@ -7,13 +7,13 @@ module ActiveMerchant #:nodoc:
|
|
7
7
|
validate if respond_to?(:validate, true)
|
8
8
|
|
9
9
|
errors.empty?
|
10
|
-
end
|
10
|
+
end
|
11
11
|
|
12
12
|
def initialize(attributes = {})
|
13
13
|
self.attributes = attributes
|
14
14
|
end
|
15
15
|
|
16
|
-
def errors
|
16
|
+
def errors
|
17
17
|
@errors ||= Errors.new(self)
|
18
18
|
end
|
19
19
|
|
@@ -22,46 +22,51 @@ module ActiveMerchant #:nodoc:
|
|
22
22
|
def attributes=(attributes)
|
23
23
|
unless attributes.nil?
|
24
24
|
for key, value in attributes
|
25
|
-
send("#{key}=", value )
|
25
|
+
send("#{key}=", value )
|
26
26
|
end
|
27
27
|
end
|
28
|
-
end
|
28
|
+
end
|
29
29
|
|
30
30
|
# This hash keeps the errors of the object
|
31
31
|
class Errors < HashWithIndifferentAccess
|
32
32
|
|
33
33
|
def initialize(base)
|
34
|
+
super() { |h, k| h[k] = [] ; h[k] }
|
34
35
|
@base = base
|
35
36
|
end
|
36
|
-
|
37
|
+
|
37
38
|
def count
|
38
39
|
size
|
39
40
|
end
|
40
41
|
|
41
|
-
|
42
|
-
|
42
|
+
def empty?
|
43
|
+
all? { |k, v| v && v.empty? }
|
44
|
+
end
|
45
|
+
|
46
|
+
# returns a specific fields error message.
|
47
|
+
# if more than one error is available we will only return the first. If no error is available
|
43
48
|
# we return an empty string
|
44
49
|
def on(field)
|
45
50
|
self[field].to_a.first
|
46
51
|
end
|
47
52
|
|
48
53
|
def add(field, error)
|
49
|
-
self[field] ||= []
|
50
54
|
self[field] << error
|
51
|
-
end
|
52
|
-
|
55
|
+
end
|
56
|
+
|
53
57
|
def add_to_base(error)
|
54
58
|
add(:base, error)
|
55
59
|
end
|
56
60
|
|
57
61
|
def each_full
|
58
|
-
full_messages.each { |msg| yield msg }
|
62
|
+
full_messages.each { |msg| yield msg }
|
59
63
|
end
|
60
64
|
|
61
65
|
def full_messages
|
62
66
|
result = []
|
63
67
|
|
64
|
-
self.each do |key, messages|
|
68
|
+
self.each do |key, messages|
|
69
|
+
next if messages.blank?
|
65
70
|
if key == 'base'
|
66
71
|
result << "#{messages.first}"
|
67
72
|
else
|
@@ -70,7 +75,7 @@ module ActiveMerchant #:nodoc:
|
|
70
75
|
end
|
71
76
|
|
72
77
|
result
|
73
|
-
end
|
74
|
-
end
|
78
|
+
end
|
79
|
+
end
|
75
80
|
end
|
76
81
|
end
|