tlconnor-activemerchant 1.20.4 → 1.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/CHANGELOG +86 -6
  2. data/CONTRIBUTORS +33 -0
  3. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +2 -0
  4. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +4 -4
  5. data/lib/active_merchant/billing/gateways/blue_pay.rb +492 -11
  6. data/lib/active_merchant/billing/gateways/braintree_blue.rb +46 -19
  7. data/lib/active_merchant/billing/gateways/certo_direct.rb +1 -1
  8. data/lib/active_merchant/billing/gateways/elavon.rb +2 -0
  9. data/lib/active_merchant/billing/gateways/epay.rb +3 -1
  10. data/lib/active_merchant/billing/gateways/itransact.rb +450 -0
  11. data/lib/active_merchant/billing/gateways/litle.rb +275 -0
  12. data/lib/active_merchant/billing/gateways/migs.rb +259 -0
  13. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  14. data/lib/active_merchant/billing/gateways/moneris.rb +4 -30
  15. data/lib/active_merchant/billing/gateways/moneris_us.rb +211 -0
  16. data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
  17. data/lib/active_merchant/billing/gateways/ogone.rb +104 -12
  18. data/lib/active_merchant/billing/gateways/orbital.rb +15 -6
  19. data/lib/active_merchant/billing/gateways/paybox_direct.rb +1 -4
  20. data/lib/active_merchant/billing/gateways/payflow.rb +8 -3
  21. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +4 -1
  22. data/lib/active_merchant/billing/gateways/payflow_express.rb +4 -2
  23. data/lib/active_merchant/billing/gateways/payment_express.rb +60 -13
  24. data/lib/active_merchant/billing/gateways/paypal.rb +3 -18
  25. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +333 -3
  26. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +245 -0
  27. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +43 -0
  28. data/lib/active_merchant/billing/gateways/paypal_express.rb +14 -65
  29. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +8 -3
  30. data/lib/active_merchant/billing/gateways/realex.rb +5 -7
  31. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +3 -2
  32. data/lib/active_merchant/billing/gateways/stripe.rb +1 -9
  33. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +2 -2
  34. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +1 -5
  35. data/lib/active_merchant/billing/gateways/viaklix.rb +7 -2
  36. data/lib/active_merchant/billing/gateways/vindicia.rb +359 -0
  37. data/lib/active_merchant/billing/integrations/dotpay.rb +22 -0
  38. data/lib/active_merchant/billing/integrations/dotpay/helper.rb +77 -0
  39. data/lib/active_merchant/billing/integrations/dotpay/notification.rb +86 -0
  40. data/lib/active_merchant/billing/integrations/dotpay/return.rb +11 -0
  41. data/lib/active_merchant/billing/integrations/epay.rb +21 -0
  42. data/lib/active_merchant/billing/integrations/epay/helper.rb +55 -0
  43. data/lib/active_merchant/billing/integrations/epay/notification.rb +110 -0
  44. data/lib/active_merchant/billing/integrations/paypal/notification.rb +2 -1
  45. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +2 -3
  46. data/lib/active_merchant/billing/integrations/robokassa.rb +49 -0
  47. data/lib/active_merchant/billing/integrations/robokassa/common.rb +19 -0
  48. data/lib/active_merchant/billing/integrations/robokassa/helper.rb +50 -0
  49. data/lib/active_merchant/billing/integrations/robokassa/notification.rb +55 -0
  50. data/lib/active_merchant/billing/integrations/robokassa/return.rb +17 -0
  51. data/lib/active_merchant/billing/integrations/two_checkout.rb +25 -3
  52. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +58 -26
  53. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +71 -46
  54. data/lib/active_merchant/billing/integrations/verkkomaksut.rb +20 -0
  55. data/lib/active_merchant/billing/integrations/verkkomaksut/helper.rb +87 -0
  56. data/lib/active_merchant/billing/integrations/verkkomaksut/notification.rb +59 -0
  57. data/lib/active_merchant/version.rb +1 -1
  58. metadata +28 -5
@@ -0,0 +1,100 @@
1
+ module ActiveMerchant
2
+ module Billing
3
+ module MigsCodes
4
+ TXN_RESPONSE_CODES = {
5
+ '?' => 'Response Unknown',
6
+ '0' => 'Transaction Successful',
7
+ '1' => 'Transaction Declined - Bank Error',
8
+ '2' => 'Bank Declined Transaction',
9
+ '3' => 'Transaction Declined - No Reply from Bank',
10
+ '4' => 'Transaction Declined - Expired Card',
11
+ '5' => 'Transaction Declined - Insufficient funds',
12
+ '6' => 'Transaction Declined - Error Communicating with Bank',
13
+ '7' => 'Payment Server Processing Error - Typically caused by invalid input data such as an invalid credit card number. Processing errors can also occur',
14
+ '8' => 'Transaction Declined - Transaction Type Not Supported',
15
+ '9' => 'Bank Declined Transaction (Do not contact Bank)',
16
+ 'A' => 'Transaction Aborted',
17
+ 'C' => 'Transaction Cancelled',
18
+ 'D' => 'Deferred Transaction',
19
+ 'E' => 'Issuer Returned a Referral Response',
20
+ 'F' => '3D Secure Authentication Failed',
21
+ 'I' => 'Card Security Code Failed',
22
+ 'L' => 'Shopping Transaction Locked (This indicates that there is another transaction taking place using the same shopping transaction number)',
23
+ 'N' => 'Cardholder is not enrolled in 3D Secure (Authentication Only)',
24
+ 'P' => 'Transaction is Pending',
25
+ 'R' => 'Retry Limits Exceeded, Transaction Not Processed',
26
+ 'S' => 'Duplicate OrderInfo used. (This is only relevant for Payment Servers that enforce the uniqueness of this field)',
27
+ 'U' => 'Card Security Code Failed'
28
+ }
29
+
30
+ ISSUER_RESPONSE_CODES = {
31
+ '00' => 'Approved',
32
+ '01' => 'Refer to Card Issuer',
33
+ '02' => 'Refer to Card Issuer',
34
+ '03' => 'Invalid Merchant',
35
+ '04' => 'Pick Up Card',
36
+ '05' => 'Do Not Honor',
37
+ '07' => 'Pick Up Card',
38
+ '12' => 'Invalid Transaction',
39
+ '14' => 'Invalid Card Number (No such Number)',
40
+ '15' => 'No Such Issuer',
41
+ '33' => 'Expired Card',
42
+ '34' => 'Suspected Fraud',
43
+ '36' => 'Restricted Card',
44
+ '39' => 'No Credit Account',
45
+ '41' => 'Card Reported Lost',
46
+ '43' => 'Stolen Card',
47
+ '51' => 'Insufficient Funds',
48
+ '54' => 'Expired Card',
49
+ '57' => 'Transaction Not Permitted',
50
+ '59' => 'Suspected Fraud',
51
+ '62' => 'Restricted Card',
52
+ '65' => 'Exceeds withdrawal frequency limit',
53
+ '91' => 'Cannot Contact Issuer'
54
+ }
55
+
56
+ VERIFIED_3D_CODES = {
57
+ 'Y' => 'The cardholder was successfully authenticated.',
58
+ 'E' => 'The cardholder is not enrolled.',
59
+ 'N' => 'The cardholder was not verified.',
60
+ 'U' => 'The cardholder\'s Issuer was unable to authenticate due to a system error at the Issuer.',
61
+ 'F' => 'An error exists in the format of the request from the merchant. For example, the request did not contain all required fields, or the format of some fields was invalid.',
62
+ 'A' => 'Authentication of your Merchant ID and Password to the Directory Server Failed (see "What does a Payment Authentication Status of "A" mean?" on page 85).',
63
+ 'D' => 'Error communicating with the Directory Server, for example, the Payment Server could not connect to the directory server or there was a versioning mismatch.',
64
+ 'C' => 'The card type is not supported for authentication.',
65
+ 'M' => 'This indicates that attempts processing was used. Verification is marked with status M - ACS attempts processing used. Payment is performed with authentication. Attempts is when a cardholder has successfully passed the directory server but decides not to continue with the authentication process and cancels.',
66
+ 'S' => 'The signature on the response received from the Issuer could not be validated. This should be considered a failure.',
67
+ 'T' => 'ACS timed out. The Issuer\'s ACS did not respond to the Authentication request within the time out period.',
68
+ 'P' => 'Error parsing input from Issuer.',
69
+ 'I' => 'Internal Payment Server system error. This could be caused by a temporary DB failure or an error in the security module or by some error in an internal system.'
70
+ }
71
+
72
+ class CreditCardType
73
+ attr_accessor :am_code, :migs_code, :migs_long_code, :name
74
+ def initialize(am_code, migs_code, migs_long_code, name)
75
+ @am_code = am_code
76
+ @migs_code = migs_code
77
+ @migs_long_code = migs_long_code
78
+ @name = name
79
+ end
80
+ end
81
+
82
+ CARD_TYPES = [
83
+ # The following are 4 different representations of credit card types
84
+ # am_code: The active merchant code
85
+ # migs_code: Used in response for purchase/authorize/status
86
+ # migs_long_code: Used to pre-select card for server_purchase_url
87
+ # name: The nice display name
88
+ %w(american_express AE Amex American\ Express),
89
+ %w(diners_club DC Dinersclub Diners\ Club),
90
+ %w(jcb JC JCB JCB\ Card),
91
+ %w(maestro MS Maestro Maestro\ Card),
92
+ %w(master MC Mastercard MasterCard),
93
+ %w(na PL PrivateLabelCard Private\ Label\ Card),
94
+ %w(visa VC Visa Visa\ Card')
95
+ ].map do |am_code, migs_code, migs_long_code, name|
96
+ CreditCardType.new(am_code, migs_code, migs_long_code, name)
97
+ end
98
+ end
99
+ end
100
+ end
@@ -101,9 +101,7 @@ module ActiveMerchant #:nodoc:
101
101
  :amount => amount(money),
102
102
  :pan => creditcard.number,
103
103
  :expdate => expdate(creditcard),
104
- :crypt_type => options[:crypt_type] || @options[:crypt_type],
105
- :cvv => creditcard.verification_value,
106
- :billing_address => options[:address] || options[:billing_address]
104
+ :crypt_type => options[:crypt_type] || @options[:crypt_type]
107
105
  }
108
106
  end
109
107
 
@@ -131,9 +129,7 @@ module ActiveMerchant #:nodoc:
131
129
 
132
130
  Response.new(successful?(response), message_from(response[:message]), response,
133
131
  :test => test?,
134
- :authorization => authorization_from(response),
135
- :avs_result => {:code => response[:avs_result_code]},
136
- :cvv_result => response[:cvd_result_code] && response[:cvd_result_code].last
132
+ :authorization => authorization_from(response)
137
133
  )
138
134
  end
139
135
 
@@ -176,32 +172,10 @@ module ActiveMerchant #:nodoc:
176
172
  actions[action].each do |key|
177
173
  transaction.add_element(key.to_s).text = parameters[key] unless parameters[key].blank?
178
174
  end
179
-
180
- add_avs_info(transaction, parameters)
181
- add_cvd_info(transaction, parameters)
182
-
175
+
183
176
  xml.to_s
184
177
  end
185
-
186
- def add_avs_info(transaction, parameters)
187
- if address = parameters[:billing_address]
188
- street_number, street_name = address[:address1].split(' ', 2)
189
-
190
- avs_info = transaction.add_element('avs_info')
191
- avs_info.add_element('avs_street_number').text = street_number
192
- avs_info.add_element('avs_street_name').text = street_name
193
- avs_info.add_element('avs_zipcode').text = address[:zip]
194
- end
195
- end
196
-
197
- def add_cvd_info(transaction, parameters)
198
- if cvd_value = parameters[:cvv]
199
- cvd_info = transaction.add_element('cvd_info')
200
- cvd_info.add_element('cvd_indicator').text = '1'
201
- cvd_info.add_element('cvd_value').text = cvd_value
202
- end
203
- end
204
-
178
+
205
179
  def message_from(message)
206
180
  return 'Unspecified error' if message.blank?
207
181
  message.gsub(/[^\w]/, ' ').split.join(" ").capitalize
@@ -0,0 +1,211 @@
1
+ require 'rexml/document'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+
6
+ # To learn more about the Moneris (US) gateway, please contact
7
+ # ussales@moneris.com for a copy of their integration guide. For
8
+ # information on remote testing, please see "Test Environment Penny Value
9
+ # Response Table", and "Test Environment eFraud (AVS and CVD) Penny
10
+ # Response Values", available at Moneris' {eSelect Plus Documentation
11
+ # Centre}[https://www3.moneris.com/connect/en/documents/index.html].
12
+ class MonerisUsGateway < Gateway
13
+ TEST_URL = 'https://esplusqa.moneris.com/gateway_us/servlet/MpgRequest'
14
+ LIVE_URL = 'https://esplus.moneris.com/gateway_us/servlet/MpgRequest'
15
+
16
+ self.supported_countries = ['US']
17
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :discover]
18
+ self.homepage_url = 'http://www.monerisusa.com/'
19
+ self.display_name = 'Moneris (US)'
20
+
21
+ # login is your Store ID
22
+ # password is your API Token
23
+ def initialize(options = {})
24
+ requires!(options, :login, :password)
25
+ @options = { :crypt_type => 7 }.update(options)
26
+ super
27
+ end
28
+
29
+ # Referred to as "PreAuth" in the Moneris integration guide, this action
30
+ # verifies and locks funds on a customer's card, which then must be
31
+ # captured at a later date.
32
+ #
33
+ # Pass in +order_id+ and optionally a +customer+ parameter.
34
+ def authorize(money, creditcard, options = {})
35
+ debit_commit 'us_preauth', money, creditcard, options
36
+ end
37
+
38
+ # This action verifies funding on a customer's card, and readies them for
39
+ # deposit in a merchant's account.
40
+ #
41
+ # Pass in <tt>order_id</tt> and optionally a <tt>customer</tt> parameter
42
+ def purchase(money, creditcard, options = {})
43
+ debit_commit 'us_purchase', money, creditcard, options
44
+ end
45
+
46
+ # This method retrieves locked funds from a customer's account (from a
47
+ # PreAuth) and prepares them for deposit in a merchant's account.
48
+ #
49
+ # Note: Moneris requires both the order_id and the transaction number of
50
+ # the original authorization. To maintain the same interface as the other
51
+ # gateways the two numbers are concatenated together with a ; separator as
52
+ # the authorization number returned by authorization
53
+ def capture(money, authorization, options = {})
54
+ commit 'us_completion', crediting_params(authorization, :comp_amount => amount(money))
55
+ end
56
+
57
+ # Voiding requires the original transaction ID and order ID of some open
58
+ # transaction. Closed transactions must be refunded. Note that the only
59
+ # methods which may be voided are +capture+ and +purchase+.
60
+ #
61
+ # Concatenate your transaction number and order_id by using a semicolon
62
+ # (';'). This is to keep the Moneris interface consistent with other
63
+ # gateways. (See +capture+ for details.)
64
+ def void(authorization, options = {})
65
+ commit 'us_purchasecorrection', crediting_params(authorization)
66
+ end
67
+
68
+ # Performs a refund. This method requires that the original transaction
69
+ # number and order number be included. Concatenate your transaction
70
+ # number and order_id by using a semicolon (';'). This is to keep the
71
+ # Moneris interface consistent with other gateways. (See +capture+ for
72
+ # details.)
73
+ def credit(money, authorization, options = {})
74
+ deprecated CREDIT_DEPRECATION_MESSAGE
75
+ refund(money, authorization, options)
76
+ end
77
+
78
+ def refund(money, authorization, options = {})
79
+ commit 'us_refund', crediting_params(authorization, :amount => amount(money))
80
+ end
81
+
82
+ def test?
83
+ @options[:test] || super
84
+ end
85
+ private # :nodoc: all
86
+
87
+ def expdate(creditcard)
88
+ sprintf("%.4i", creditcard.year)[-2..-1] + sprintf("%.2i", creditcard.month)
89
+ end
90
+
91
+ def debit_commit(commit_type, money, creditcard, options)
92
+ requires!(options, :order_id)
93
+ commit(commit_type, debit_params(money, creditcard, options))
94
+ end
95
+
96
+ # Common params used amongst the +purchase+ and +authorization+ methods
97
+ def debit_params(money, creditcard, options = {})
98
+ {
99
+ :order_id => options[:order_id],
100
+ :cust_id => options[:customer],
101
+ :amount => amount(money),
102
+ :pan => creditcard.number,
103
+ :expdate => expdate(creditcard),
104
+ :crypt_type => options[:crypt_type] || @options[:crypt_type]
105
+ }
106
+ end
107
+
108
+ # Common params used amongst the +credit+, +void+ and +capture+ methods
109
+ def crediting_params(authorization, options = {})
110
+ {
111
+ :txn_number => split_authorization(authorization).first,
112
+ :order_id => split_authorization(authorization).last,
113
+ :crypt_type => options[:crypt_type] || @options[:crypt_type]
114
+ }.merge(options)
115
+ end
116
+
117
+ # Splits an +authorization+ param and retrives the order id and
118
+ # transaction number in that order.
119
+ def split_authorization(authorization)
120
+ if authorization.nil? || authorization.empty? || authorization !~ /;/
121
+ raise ArgumentError, 'You must include a valid authorization code (e.g. "1234;567")'
122
+ else
123
+ authorization.split(';')
124
+ end
125
+ end
126
+
127
+ def commit(action, parameters = {})
128
+ response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, post_data(action, parameters)))
129
+
130
+ Response.new(successful?(response), message_from(response[:message]), response,
131
+ :test => test?,
132
+ :authorization => authorization_from(response)
133
+ )
134
+ end
135
+
136
+ # Generates a Moneris authorization string of the form 'trans_id;receipt_id'.
137
+ def authorization_from(response = {})
138
+ if response[:trans_id] && response[:receipt_id]
139
+ "#{response[:trans_id]};#{response[:receipt_id]}"
140
+ end
141
+ end
142
+
143
+ # Tests for a successful response from Moneris' servers
144
+ def successful?(response)
145
+ response[:response_code] &&
146
+ response[:complete] &&
147
+ (0..49).include?(response[:response_code].to_i)
148
+ end
149
+
150
+ def parse(xml)
151
+ response = { :message => "Global Error Receipt", :complete => false }
152
+ hashify_xml!(xml, response)
153
+ response
154
+ end
155
+
156
+ def hashify_xml!(xml, response)
157
+ xml = REXML::Document.new(xml)
158
+ return if xml.root.nil?
159
+ xml.elements.each('//receipt/*') do |node|
160
+ response[node.name.underscore.to_sym] = normalize(node.text)
161
+ end
162
+ end
163
+
164
+ def post_data(action, parameters = {})
165
+ xml = REXML::Document.new
166
+ root = xml.add_element("request")
167
+ root.add_element("store_id").text = options[:login]
168
+ root.add_element("api_token").text = options[:password]
169
+ transaction = root.add_element(action)
170
+
171
+ # Must add the elements in the correct order
172
+ actions[action].each do |key|
173
+ transaction.add_element(key.to_s).text = parameters[key] unless parameters[key].blank?
174
+ end
175
+
176
+ xml.to_s
177
+ end
178
+
179
+ def message_from(message)
180
+ return 'Unspecified error' if message.blank?
181
+ message.gsub(/[^\w]/, ' ').split.join(" ").capitalize
182
+ end
183
+
184
+ # Make a Ruby type out of the response string
185
+ def normalize(field)
186
+ case field
187
+ when "true" then true
188
+ when "false" then false
189
+ when '', "null" then nil
190
+ else field
191
+ end
192
+ end
193
+
194
+ def actions
195
+ {
196
+ "us_purchase" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type],
197
+ "us_preauth" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type],
198
+ "us_refund" => [:order_id, :amount, :txn_number, :crypt_type],
199
+ "us_ind_refund" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type],
200
+ "us_completion" => [:order_id, :comp_amount, :txn_number, :crypt_type],
201
+ "us_purchasecorrection" => [:order_id, :txn_number, :crypt_type],
202
+ "us_cavv_purchase" => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv],
203
+ "us_cavv_preauth" => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv],
204
+ "us_batchcloseall" => [],
205
+ "us_opentotals" => [:ecr_number],
206
+ "us_batchclose" => [:ecr_number]
207
+ }
208
+ end
209
+ end
210
+ end
211
+ end
@@ -59,7 +59,7 @@ module ActiveMerchant #:nodoc:
59
59
  end
60
60
 
61
61
  def purchase(money, credit_card_or_stored_id, options = {})
62
- if credit_card_or_stored_id.is_a?(ActiveMerchant::Billing::CreditCard)
62
+ if credit_card_or_stored_id.respond_to?(:number)
63
63
  #Credit card for instant payment
64
64
  commit :purchase, build_purchase_request(money, credit_card_or_stored_id, options)
65
65
  else
@@ -9,17 +9,23 @@ module ActiveMerchant #:nodoc:
9
9
  # communication between Ogone systems and your e-commerce website.
10
10
  #
11
11
  # This implementation follows the specification provided in the DirectLink integration
12
- # guide version 4.2.0 (26 October 2011), available here:
12
+ # guide version 4.3.0 (25 April 2012), available here:
13
13
  # https://secure.ogone.com/ncol/Ogone_DirectLink_EN.pdf
14
14
  #
15
15
  # It also features aliases, which allow to store/unstore credit cards, as specified in
16
- # the Alias Manager Option guide version 3.2.0 (26 October 2011) available here:
16
+ # the Alias Manager Option guide version 3.2.1 (25 April 2012) available here:
17
17
  # https://secure.ogone.com/ncol/Ogone_Alias_EN.pdf
18
18
  #
19
- # It was last tested on Release 4.89 of Ogone DirectLink + AliasManager (26 October 2011).
19
+ # It also implements the 3-D Secure feature, as specified in the DirectLink with
20
+ # 3-D Secure guide version 3.0 (25 April 2012) available here:
21
+ # https://secure.ogone.com/ncol/Ogone_DirectLink-3-D_EN.pdf
22
+ #
23
+ # It was last tested on Release 4.92 of Ogone DirectLink + AliasManager + Direct Link 3D
24
+ # (25 April 2012).
20
25
  #
21
26
  # For any questions or comments, please contact one of the following:
22
- # - Nicolas Jacobeus (nj@belighted.com),
27
+ # - Joel Cogen (joel.cogen@belighted.com)
28
+ # - Nicolas Jacobeus (nicolas.jacobeus@belighted.com),
23
29
  # - Sébastien Grosjean (public@zencocoon.com),
24
30
  # - Rémy Coutable (remy@jilion.com).
25
31
  #
@@ -52,17 +58,46 @@ module ActiveMerchant #:nodoc:
52
58
  # puts response.success? # Check whether the transaction was successful
53
59
  # puts response.message # Retrieve the message returned by Ogone
54
60
  # puts response.authorization # Retrieve the unique transaction ID returned by Ogone
61
+ # puts response.order_id # Retrieve the order ID
55
62
  #
56
63
  # == Alias feature
57
64
  #
58
- # To use the alias feature, simply add :store in the options hash:
65
+ # To use the alias feature, simply add :billing_id in the options hash:
59
66
  #
60
67
  # # Associate the alias to that credit card
61
- # gateway.purchase(1000, creditcard, :order_id => "1", :store => "myawesomecustomer")
68
+ # gateway.purchase(1000, creditcard, :order_id => "1", :billing_id => "myawesomecustomer")
62
69
  #
63
70
  # # You can use the alias instead of the credit card for subsequent orders
64
71
  # gateway.purchase(2000, "myawesomecustomer", :order_id => "2")
65
72
  #
73
+ # # You can also create an alias without making a purchase using store
74
+ # gateway.store(creditcard, :billing_id => "myawesomecustomer")
75
+ #
76
+ # # When using store, you can also let Ogone generate the alias for you
77
+ # response = gateway.store(creditcard)
78
+ # puts response.billing_id # Retrieve the generated alias
79
+ #
80
+ # == 3-D Secure feature
81
+ #
82
+ # To use the 3-D Secure feature, simply add :d3d => true in the options hash:
83
+ # gateway.purchase(2000, "myawesomecustomer", :order_id => "2", :d3d => true)
84
+ #
85
+ # Specific 3-D Secure request options are (please refer to the documentation for more infos about these options):
86
+ # :win_3ds => :main_window (default), :pop_up or :pop_ix.
87
+ # :http_accept => "*/*" (default), or any other HTTP_ACCEPT header value.
88
+ # :http_user_agent => The cardholder's User-Agent string
89
+ # :accept_url => URL of the web page to show the customer when the payment is authorized.
90
+ # (or waiting to be authorized).
91
+ # :decline_url => URL of the web page to show the customer when the acquirer rejects the authorization
92
+ # more than the maximum permitted number of authorization attempts (10 by default, but can
93
+ # be changed in the "Global transaction parameters" tab, "Payment retry" section of the
94
+ # Technical Information page).
95
+ # :exception_url => URL of the web page to show the customer when the payment result is uncertain.
96
+ # :paramplus => Field to submit the miscellaneous parameters and their values that you wish to be
97
+ # returned in the post sale request or final redirection.
98
+ # :complus => Field to submit a value you wish to be returned in the post sale request or output.
99
+ # :language => Customer's language, for example: "en_EN"
100
+ #
66
101
  class OgoneGateway < Gateway
67
102
 
68
103
  URLS = {
@@ -80,8 +115,16 @@ module ActiveMerchant #:nodoc:
80
115
 
81
116
  SUCCESS_MESSAGE = "The transaction was successful"
82
117
 
118
+ THREE_D_SECURE_DISPLAY_WAYS = { :main_window => 'MAINW', # display the identification page in the main window
119
+ # (default value).
120
+ :pop_up => 'POPUP', # display the identification page in a pop-up window
121
+ # and return to the main window at the end.
122
+ :pop_ix => 'POPIX' } # display the identification page in a pop-up window
123
+ # and remain in the pop-up window.
124
+
83
125
  OGONE_NO_SIGNATURE_DEPRECATION_MESSAGE = "Signature usage will be required from a future release of ActiveMerchant's Ogone Gateway. Please update your Ogone account to use it."
84
126
  OGONE_LOW_ENCRYPTION_DEPRECATION_MESSAGE = "SHA512 signature encryptor will be required from a future release of ActiveMerchant's Ogone Gateway. Please update your Ogone account to use it."
127
+ OGONE_STORE_OPTION_DEPRECATION_MESSAGE = "The 'store' option has been renamed to 'billing_id', and its usage is deprecated."
85
128
 
86
129
  self.supported_countries = ['BE', 'DE', 'FR', 'NL', 'AT', 'CH']
87
130
  # also supports Airplus and UATP
@@ -152,6 +195,14 @@ module ActiveMerchant #:nodoc:
152
195
  perform_reference_credit(money, reference, options)
153
196
  end
154
197
 
198
+ # Store a credit card by creating an Ogone Alias
199
+ def store(payment_source, options = {})
200
+ options.merge!(:alias_operation => 'BYOGONE') unless options.has_key?(:billing_id) || options.has_key?(:store)
201
+ response = authorize(1, payment_source, options)
202
+ void(response.authorization) if response.success?
203
+ response
204
+ end
205
+
155
206
  def test?
156
207
  @options[:test] || super
157
208
  end
@@ -164,7 +215,7 @@ module ActiveMerchant #:nodoc:
164
215
 
165
216
  def reference_transaction?(identifier)
166
217
  return false unless identifier.is_a?(String)
167
- reference, action = identifier.split(";")
218
+ _, action = identifier.split(";")
168
219
  !action.nil?
169
220
  end
170
221
 
@@ -188,21 +239,44 @@ module ActiveMerchant #:nodoc:
188
239
 
189
240
  def add_payment_source(post, payment_source, options)
190
241
  if payment_source.is_a?(String)
191
- add_alias(post, payment_source)
242
+ add_alias(post, payment_source, options[:alias_operation])
192
243
  add_eci(post, options[:eci] || '9')
193
244
  else
194
- add_alias(post, options[:store])
245
+ if options.has_key?(:store)
246
+ deprecated OGONE_STORE_OPTION_DEPRECATION_MESSAGE
247
+ options[:billing_id] ||= options[:store]
248
+ end
249
+ add_alias(post, options[:billing_id], options[:alias_operation])
195
250
  add_eci(post, options[:eci] || '7')
251
+ add_d3d(post, options) if options[:d3d]
196
252
  add_creditcard(post, payment_source)
197
253
  end
198
254
  end
199
255
 
256
+ def add_d3d(post, options)
257
+ add_pair post, 'FLAG3D', 'Y'
258
+ win_3ds = THREE_D_SECURE_DISPLAY_WAYS.key?(options[:win_3ds]) ?
259
+ THREE_D_SECURE_DISPLAY_WAYS[options[:win_3ds]] :
260
+ THREE_D_SECURE_DISPLAY_WAYS[:main_window]
261
+ add_pair post, 'WIN3DS', win_3ds
262
+
263
+ add_pair post, 'HTTP_ACCEPT', options[:http_accept] || "*/*"
264
+ add_pair post, 'HTTP_USER_AGENT', options[:http_user_agent] if options[:http_user_agent]
265
+ add_pair post, 'ACCEPTURL', options[:accept_url] if options[:accept_url]
266
+ add_pair post, 'DECLINEURL', options[:decline_url] if options[:decline_url]
267
+ add_pair post, 'EXCEPTIONURL', options[:exception_url] if options[:exception_url]
268
+ add_pair post, 'PARAMPLUS', options[:paramplus] if options[:paramplus]
269
+ add_pair post, 'COMPLUS', options[:complus] if options[:complus]
270
+ add_pair post, 'LANGUAGE', options[:language] if options[:language]
271
+ end
272
+
200
273
  def add_eci(post, eci)
201
274
  add_pair post, 'ECI', eci.to_s
202
275
  end
203
276
 
204
- def add_alias(post, _alias)
277
+ def add_alias(post, _alias, alias_operation = nil)
205
278
  add_pair post, 'ALIAS', _alias
279
+ add_pair post, 'ALIASOPERATION', alias_operation unless alias_operation.nil?
206
280
  end
207
281
 
208
282
  def add_authorization(post, authorization)
@@ -242,7 +316,15 @@ module ActiveMerchant #:nodoc:
242
316
 
243
317
  def parse(body)
244
318
  xml_root = REXML::Document.new(body).root
245
- convert_attributes_to_hash(xml_root.attributes)
319
+ response = convert_attributes_to_hash(xml_root.attributes)
320
+
321
+ # Add HTML_ANSWER element (3-D Secure specific to the response's params)
322
+ # Note: HTML_ANSWER is not an attribute so we add it "by hand" to the response
323
+ if html_answer = REXML::XPath.first(xml_root, "//HTML_ANSWER")
324
+ response["HTML_ANSWER"] = html_answer.text
325
+ end
326
+
327
+ response
246
328
  end
247
329
 
248
330
  def commit(action, parameters)
@@ -259,7 +341,7 @@ module ActiveMerchant #:nodoc:
259
341
  :avs_result => { :code => AVS_MAPPING[response["AAVCheck"]] },
260
342
  :cvv_result => CVV_MAPPING[response["CVCCheck"]]
261
343
  }
262
- Response.new(successful?(response), message_from(response), response, options)
344
+ OgoneResponse.new(successful?(response), message_from(response), response, options)
263
345
  end
264
346
 
265
347
  def successful?(response)
@@ -326,5 +408,15 @@ module ActiveMerchant #:nodoc:
326
408
  response_hash
327
409
  end
328
410
  end
411
+
412
+ class OgoneResponse < Response
413
+ def order_id
414
+ @params['orderID']
415
+ end
416
+
417
+ def billing_id
418
+ @params['ALIAS']
419
+ end
420
+ end
329
421
  end
330
422
  end