tlconnor-activemerchant 1.20.4 → 1.23.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/CHANGELOG +86 -6
- data/CONTRIBUTORS +33 -0
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +2 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +4 -4
- data/lib/active_merchant/billing/gateways/blue_pay.rb +492 -11
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +46 -19
- data/lib/active_merchant/billing/gateways/certo_direct.rb +1 -1
- data/lib/active_merchant/billing/gateways/elavon.rb +2 -0
- data/lib/active_merchant/billing/gateways/epay.rb +3 -1
- data/lib/active_merchant/billing/gateways/itransact.rb +450 -0
- data/lib/active_merchant/billing/gateways/litle.rb +275 -0
- data/lib/active_merchant/billing/gateways/migs.rb +259 -0
- data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +4 -30
- data/lib/active_merchant/billing/gateways/moneris_us.rb +211 -0
- data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
- data/lib/active_merchant/billing/gateways/ogone.rb +104 -12
- data/lib/active_merchant/billing/gateways/orbital.rb +15 -6
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +1 -4
- data/lib/active_merchant/billing/gateways/payflow.rb +8 -3
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +4 -1
- data/lib/active_merchant/billing/gateways/payflow_express.rb +4 -2
- data/lib/active_merchant/billing/gateways/payment_express.rb +60 -13
- data/lib/active_merchant/billing/gateways/paypal.rb +3 -18
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +333 -3
- data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +245 -0
- data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +43 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +14 -65
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +8 -3
- data/lib/active_merchant/billing/gateways/realex.rb +5 -7
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +3 -2
- data/lib/active_merchant/billing/gateways/stripe.rb +1 -9
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +2 -2
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +1 -5
- data/lib/active_merchant/billing/gateways/viaklix.rb +7 -2
- data/lib/active_merchant/billing/gateways/vindicia.rb +359 -0
- data/lib/active_merchant/billing/integrations/dotpay.rb +22 -0
- data/lib/active_merchant/billing/integrations/dotpay/helper.rb +77 -0
- data/lib/active_merchant/billing/integrations/dotpay/notification.rb +86 -0
- data/lib/active_merchant/billing/integrations/dotpay/return.rb +11 -0
- data/lib/active_merchant/billing/integrations/epay.rb +21 -0
- data/lib/active_merchant/billing/integrations/epay/helper.rb +55 -0
- data/lib/active_merchant/billing/integrations/epay/notification.rb +110 -0
- data/lib/active_merchant/billing/integrations/paypal/notification.rb +2 -1
- data/lib/active_merchant/billing/integrations/quickpay/helper.rb +2 -3
- data/lib/active_merchant/billing/integrations/robokassa.rb +49 -0
- data/lib/active_merchant/billing/integrations/robokassa/common.rb +19 -0
- data/lib/active_merchant/billing/integrations/robokassa/helper.rb +50 -0
- data/lib/active_merchant/billing/integrations/robokassa/notification.rb +55 -0
- data/lib/active_merchant/billing/integrations/robokassa/return.rb +17 -0
- data/lib/active_merchant/billing/integrations/two_checkout.rb +25 -3
- data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +58 -26
- data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +71 -46
- data/lib/active_merchant/billing/integrations/verkkomaksut.rb +20 -0
- data/lib/active_merchant/billing/integrations/verkkomaksut/helper.rb +87 -0
- data/lib/active_merchant/billing/integrations/verkkomaksut/notification.rb +59 -0
- data/lib/active_merchant/version.rb +1 -1
- 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.
|
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.
|
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.
|
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
|
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
|
-
# -
|
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 :
|
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", :
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|