activemerchant 1.14.0 → 1.15.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.
Files changed (39) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +18 -0
  3. data/CONTRIBUTORS +4 -0
  4. data/README.rdoc +1 -0
  5. data/lib/active_merchant.rb +1 -1
  6. data/lib/active_merchant/billing/credit_card.rb +53 -42
  7. data/lib/active_merchant/billing/gateway.rb +6 -6
  8. data/lib/active_merchant/billing/gateways/authorize_net.rb +4 -2
  9. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +3 -3
  11. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +1 -1
  12. data/lib/active_merchant/billing/gateways/bogus.rb +12 -0
  13. data/lib/active_merchant/billing/gateways/braintree_blue.rb +77 -16
  14. data/lib/active_merchant/billing/gateways/eway.rb +0 -4
  15. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +1 -1
  17. data/lib/active_merchant/billing/gateways/orbital.rb +1 -1
  18. data/lib/active_merchant/billing/gateways/pay_junction.rb +1 -1
  19. data/lib/active_merchant/billing/gateways/payflow.rb +22 -8
  20. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +10 -10
  21. data/lib/active_merchant/billing/gateways/payflow_express.rb +115 -36
  22. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
  23. data/lib/active_merchant/billing/gateways/qbms.rb +1 -1
  24. data/lib/active_merchant/billing/gateways/realex.rb +7 -20
  25. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +5 -5
  26. data/lib/active_merchant/billing/gateways/viaklix.rb +1 -1
  27. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +18 -10
  28. data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
  29. data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
  30. data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
  31. data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
  32. data/lib/active_merchant/billing/integrations/helper.rb +4 -4
  33. data/lib/active_merchant/billing/integrations/notification.rb +1 -1
  34. data/lib/active_merchant/common/post_data.rb +1 -1
  35. data/lib/active_merchant/common/posts_data.rb +1 -1
  36. data/lib/active_merchant/common/validateable.rb +20 -15
  37. data/lib/active_merchant/version.rb +1 -1
  38. metadata +20 -21
  39. 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
- class_inheritable_accessor :request_timeout
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
- class_inheritable_accessor :test_url, :live_url, :delimiter, :actions
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
- full_name = "#{params[:first_name]} #{params[:last_name]}"
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 << " #{params[:address2]}" if params[:address2]
126
- params[:address1] = address
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 && params[:name].blank?
131
- add_field(mappings[:shipping_address][:name], fields[mappings[:customer][:name]])
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
@@ -0,0 +1,11 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Directebanking
5
+ class Return < ActiveMerchant::Billing::Integrations::Return
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
11
+
@@ -3,14 +3,14 @@ module ActiveMerchant #:nodoc:
3
3
  module Integrations #:nodoc:
4
4
  class Helper #:nodoc:
5
5
  attr_reader :fields
6
- class_inheritable_accessor :service_url
7
- class_inheritable_hash :mappings
8
- class_inheritable_accessor :country_format
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
- class_inheritable_accessor :application_id
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
- class_inheritable_accessor :production_ips
9
+ class_attribute :production_ips
10
10
 
11
11
  def initialize(post, options = {})
12
12
  @options = options
@@ -2,7 +2,7 @@ require 'cgi'
2
2
 
3
3
  module ActiveMerchant
4
4
  class PostData < Hash
5
- class_inheritable_accessor :required_fields, :instance_writer => false
5
+ class_attribute :required_fields, :instance_writer => false
6
6
  self.required_fields = []
7
7
 
8
8
  def []=(key, value)
@@ -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.class_inheritable_accessor :retry_safe
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
- # returns a specific fields error message.
42
- # if more than one error is available we will only return the first. If no error is available
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