activemerchant 1.56.0 → 1.66.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +331 -0
- data/README.md +9 -9
- data/lib/active_merchant/billing/check.rb +3 -0
- data/lib/active_merchant/billing/credit_card.rb +8 -3
- data/lib/active_merchant/billing/credit_card_methods.rb +41 -1
- data/lib/active_merchant/billing/gateway.rb +14 -6
- data/lib/active_merchant/billing/gateways/adyen.rb +228 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +157 -44
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +7 -4
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +283 -0
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +68 -2
- data/lib/active_merchant/billing/gateways/blue_pay.rb +2 -2
- data/lib/active_merchant/billing/gateways/blue_snap.rb +348 -0
- data/lib/active_merchant/billing/gateways/bpoint.rb +1 -1
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +58 -20
- data/lib/active_merchant/billing/gateways/bridge_pay.rb +37 -8
- data/lib/active_merchant/billing/gateways/card_stream.rb +161 -40
- data/lib/active_merchant/billing/gateways/cashnet.rb +1 -0
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +5 -2
- data/lib/active_merchant/billing/gateways/citrus_pay.rb +24 -0
- data/lib/active_merchant/billing/gateways/clearhaus.rb +24 -40
- data/lib/active_merchant/billing/gateways/conekta.rb +6 -1
- data/lib/active_merchant/billing/gateways/creditcall.rb +1 -1
- data/lib/active_merchant/billing/gateways/credorax.rb +310 -0
- data/lib/active_merchant/billing/gateways/culqi.rb +279 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +80 -64
- data/lib/active_merchant/billing/gateways/data_cash.rb +10 -304
- data/lib/active_merchant/billing/gateways/digitzs.rb +292 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +40 -26
- data/lib/active_merchant/billing/gateways/element.rb +356 -0
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +16 -2
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +6 -1
- data/lib/active_merchant/billing/gateways/forte.rb +10 -2
- data/lib/active_merchant/billing/gateways/global_collect.rb +311 -0
- data/lib/active_merchant/billing/gateways/global_transport.rb +1 -0
- data/lib/active_merchant/billing/gateways/iats_payments.rb +13 -0
- data/lib/active_merchant/billing/gateways/in_context_paypal_express.rb +15 -0
- data/lib/active_merchant/billing/gateways/iveri.rb +251 -0
- data/lib/active_merchant/billing/gateways/jetpay.rb +33 -19
- data/lib/active_merchant/billing/gateways/kushki.rb +217 -0
- data/lib/active_merchant/billing/gateways/latitude19.rb +416 -0
- data/lib/active_merchant/billing/gateways/linkpoint.rb +2 -0
- data/lib/active_merchant/billing/gateways/litle.rb +29 -13
- data/lib/active_merchant/billing/gateways/mastercard.rb +268 -0
- data/lib/active_merchant/billing/gateways/maxipago.rb +145 -122
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +15 -1
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +10 -7
- data/lib/active_merchant/billing/gateways/mercury.rb +13 -5
- data/lib/active_merchant/billing/gateways/metrics_global.rb +1 -1
- data/lib/active_merchant/billing/gateways/migs.rb +23 -1
- data/lib/active_merchant/billing/gateways/monei.rb +1 -1
- data/lib/active_merchant/billing/gateways/moneris.rb +21 -1
- data/lib/active_merchant/billing/gateways/nab_transact.rb +12 -0
- data/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +165 -0
- data/lib/active_merchant/billing/gateways/netbanx.rb +245 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +30 -9
- data/lib/active_merchant/billing/gateways/omise.rb +9 -5
- data/lib/active_merchant/billing/gateways/openpay.rb +10 -1
- data/lib/active_merchant/billing/gateways/opp.rb +362 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +28 -7
- data/lib/active_merchant/billing/gateways/pagarme.rb +248 -0
- data/lib/active_merchant/billing/gateways/pay_junction_v2.rb +190 -0
- data/lib/active_merchant/billing/gateways/payeezy.rb +61 -12
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
- data/lib/active_merchant/billing/gateways/payflow.rb +6 -0
- data/lib/active_merchant/billing/gateways/payment_express.rb +1 -1
- data/lib/active_merchant/billing/gateways/paymill.rb +29 -11
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
- data/lib/active_merchant/billing/gateways/paypal_express.rb +1 -6
- data/lib/active_merchant/billing/gateways/payu_in.rb +3 -2
- data/lib/active_merchant/billing/gateways/payu_latam.rb +402 -0
- data/lib/active_merchant/billing/gateways/pin.rb +6 -3
- data/lib/active_merchant/billing/gateways/pro_pay.rb +326 -0
- data/lib/active_merchant/billing/gateways/psl_card.rb +3 -3
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +1 -1
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +0 -2
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +1 -1
- data/lib/active_merchant/billing/gateways/quickpay.rb +3 -3
- data/lib/active_merchant/billing/gateways/qvalent.rb +44 -1
- data/lib/active_merchant/billing/gateways/redsys.rb +3 -0
- data/lib/active_merchant/billing/gateways/s5.rb +8 -5
- data/lib/active_merchant/billing/gateways/safe_charge.rb +220 -0
- data/lib/active_merchant/billing/gateways/sage.rb +397 -128
- data/lib/active_merchant/billing/gateways/sage_pay.rb +45 -20
- data/lib/active_merchant/billing/gateways/secure_net.rb +0 -5
- data/lib/active_merchant/billing/gateways/secure_pay.rb +1 -1
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +12 -0
- data/lib/active_merchant/billing/gateways/securion_pay.rb +46 -17
- data/lib/active_merchant/billing/gateways/stripe.rb +125 -29
- data/lib/active_merchant/billing/gateways/telr.rb +275 -0
- data/lib/active_merchant/billing/gateways/tns.rb +13 -222
- data/lib/active_merchant/billing/gateways/trans_first.rb +40 -16
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +606 -0
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +114 -9
- data/lib/active_merchant/billing/gateways/vanco.rb +14 -10
- data/lib/active_merchant/billing/gateways/visanet_peru.rb +209 -0
- data/lib/active_merchant/billing/gateways/wepay.rb +73 -38
- data/lib/active_merchant/billing/gateways/wirecard.rb +1 -0
- data/lib/active_merchant/billing/gateways/world_net.rb +344 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +48 -16
- data/lib/active_merchant/billing/network_tokenization_credit_card.rb +15 -0
- data/lib/active_merchant/country.rb +6 -4
- data/lib/active_merchant/posts_data.rb +1 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +32 -13
- data/lib/active_merchant/billing/gateways/app55.rb +0 -176
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +0 -314
- data/lib/active_merchant/billing/gateways/certo_direct.rb +0 -278
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +0 -89
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +0 -115
- data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +0 -149
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +0 -97
@@ -0,0 +1,228 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class AdyenGateway < Gateway
|
4
|
+
|
5
|
+
# we recommend setting up merchant-specific endpoints.
|
6
|
+
# https://docs.adyen.com/developers/api-manual#apiendpoints
|
7
|
+
self.test_url = 'https://pal-test.adyen.com/pal/servlet/Payment/v18'
|
8
|
+
self.live_url = 'https://pal-live.adyen.com/pal/servlet/Payment/v18'
|
9
|
+
|
10
|
+
self.supported_countries = ['AD','AE','AF','AG','AI','AL','AM','AO','AQ','AR','AS','AT','AU','AW','AX','AZ','BA','BB','BD','BE','BF','BG','BH','BI','BJ','BL','BM','BN','BO','BQ','BR','BS','BT','BV','BW','BY','BZ','CA','CC','CD','CF','CG','CH','CI','CK','CL','CM','CN','CO','CR','CU','CV','CW','CX','CY','CZ','DE','DJ','DK','DM','DO','DZ','EC','EE','EG','EH','ER','ES','ET','FI','FJ','FK','FM','FO','FR','GA','GB','GD','GE','GF','GG','GH','GI','GL','GM','GN','GP','GQ','GR','GS','GT','GU','GW','GY','HK','HM','HN','HR','HT','HU','ID','IE','IL','IM','IN','IO','IQ','IR','IS','IT','JE','JM','JO','JP','KE','KG','KH','KI','KM','KN','KP','KR','KW','KY','KZ','LA','LB','LC','LI','LK','LR','LS','LT','LU','LV','LY','MA','MC','MD','ME','MF','MG','MH','MK','ML','MM','MN','MO','MP','MQ','MR','MS','MT','MU','MV','MW','MX','MY','MZ','NA','NC','NE','NF','NG','NI','NL','NO','NP','NR','NU','NZ','OM','PA','PE','PF','PG','PH','PK','PL','PM','PN','PR','PS','PT','PW','PY','QA','RE','RO','RS','RU','RW','SA','SB','SC','SD','SE','SG','SH','SI','SJ','SK','SL','SM','SN','SO','SR','SS','ST','SV','SX','SY','SZ','TC','TD','TF','TG','TH','TJ','TK','TL','TM','TN','TO','TR','TT','TV','TW','TZ','UA','UG','UM','US','UY','UZ','VA','VC','VE','VG','VI','VN','VU','WF','WS','YE','YT','ZA','ZM','ZW']
|
11
|
+
self.default_currency = 'USD'
|
12
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb, :dankort, :maestro, :discover]
|
13
|
+
|
14
|
+
self.money_format = :cents
|
15
|
+
|
16
|
+
self.homepage_url = 'https://www.adyen.com/'
|
17
|
+
self.display_name = 'Adyen'
|
18
|
+
|
19
|
+
STANDARD_ERROR_CODE_MAPPING = {
|
20
|
+
'101' => STANDARD_ERROR_CODE[:incorrect_number],
|
21
|
+
'103' => STANDARD_ERROR_CODE[:invalid_cvc],
|
22
|
+
'131' => STANDARD_ERROR_CODE[:incorrect_address],
|
23
|
+
'132' => STANDARD_ERROR_CODE[:incorrect_address],
|
24
|
+
'133' => STANDARD_ERROR_CODE[:incorrect_address],
|
25
|
+
'134' => STANDARD_ERROR_CODE[:incorrect_address],
|
26
|
+
'135' => STANDARD_ERROR_CODE[:incorrect_address],
|
27
|
+
}
|
28
|
+
|
29
|
+
def initialize(options={})
|
30
|
+
requires!(options, :username, :password, :merchant_account)
|
31
|
+
@username, @password, @merchant_account = options.values_at(:username, :password, :merchant_account)
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
def purchase(money, payment, options={})
|
36
|
+
MultiResponse.run do |r|
|
37
|
+
r.process{authorize(money, payment, options)}
|
38
|
+
r.process{capture(money, r.authorization, options)}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def authorize(money, payment, options={})
|
43
|
+
requires!(options, :reference)
|
44
|
+
post = init_post(options)
|
45
|
+
add_invoice(post, money, options)
|
46
|
+
add_payment(post, payment)
|
47
|
+
add_extra_data(post, options)
|
48
|
+
add_address(post, options)
|
49
|
+
commit('authorise', post)
|
50
|
+
end
|
51
|
+
|
52
|
+
def capture(money, authorization, options={})
|
53
|
+
post = init_post(options)
|
54
|
+
add_invoice_for_modification(post, money, authorization, options)
|
55
|
+
add_references(post, authorization, options)
|
56
|
+
commit('capture', post)
|
57
|
+
end
|
58
|
+
|
59
|
+
def refund(money, authorization, options={})
|
60
|
+
post = init_post(options)
|
61
|
+
add_invoice_for_modification(post, money, authorization, options)
|
62
|
+
add_references(post, authorization, options)
|
63
|
+
commit('refund', post)
|
64
|
+
end
|
65
|
+
|
66
|
+
def void(authorization, options={})
|
67
|
+
post = init_post(options)
|
68
|
+
add_references(post, authorization, options)
|
69
|
+
commit('cancel', post)
|
70
|
+
end
|
71
|
+
|
72
|
+
def verify(credit_card, options={})
|
73
|
+
MultiResponse.run(:use_first_response) do |r|
|
74
|
+
r.process { authorize(100, credit_card, options) }
|
75
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def supports_scrubbing?
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def scrub(transcript)
|
84
|
+
transcript.
|
85
|
+
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
|
86
|
+
gsub(%r(("number\\?":\\?")[^"]*)i, '\1[FILTERED]').
|
87
|
+
gsub(%r(("cvc\\?":\\?")[^"]*)i, '\1[FILTERED]')
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def add_extra_data(post, options)
|
93
|
+
post[:shopperEmail] = options[:shopper_email] if options[:shopper_email]
|
94
|
+
post[:shopperIP] = options[:shopper_ip] if options[:shopper_ip]
|
95
|
+
post[:shopperReference] = options[:shopper_reference] if options[:shopper_reference]
|
96
|
+
post[:fraudOffset] = options[:fraud_offset] if options[:fraud_offset]
|
97
|
+
post[:selectedBrand] = options[:selected_brand] if options[:selected_brand]
|
98
|
+
post[:deliveryDate] = options[:delivery_date] if options[:delivery_date]
|
99
|
+
post[:merchantOrderReference] = options[:merchant_order_reference] if options[:merchant_order_reference]
|
100
|
+
post[:shopperInteraction] = options[:shopper_interaction] if options[:shopper_interaction]
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_address(post, options)
|
104
|
+
return unless post[:card] && post[:card].kind_of?(Hash)
|
105
|
+
if address = options[:billing_address] || options[:address]
|
106
|
+
post[:card][:billingAddress] = {}
|
107
|
+
post[:card][:billingAddress][:street] = address[:address1] if address[:address1]
|
108
|
+
post[:card][:billingAddress][:houseNumberOrName] = address[:address2] if address[:address2]
|
109
|
+
post[:card][:billingAddress][:postalCode] = address[:zip] if address[:zip]
|
110
|
+
post[:card][:billingAddress][:city] = address[:city] if address[:city]
|
111
|
+
post[:card][:billingAddress][:stateOrProvince] = address[:state] if address[:state]
|
112
|
+
post[:card][:billingAddress][:country] = address[:country] if address[:country]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def add_invoice(post, money, options)
|
117
|
+
amount = {
|
118
|
+
value: amount(money),
|
119
|
+
currency: options[:currency] || currency(money)
|
120
|
+
}
|
121
|
+
post[:reference] = options[:reference]
|
122
|
+
post[:amount] = amount
|
123
|
+
end
|
124
|
+
|
125
|
+
def add_invoice_for_modification(post, money, authorization, options)
|
126
|
+
amount = {
|
127
|
+
value: amount(money),
|
128
|
+
currency: options[:currency] || currency(money)
|
129
|
+
}
|
130
|
+
post[:modificationAmount] = amount
|
131
|
+
end
|
132
|
+
|
133
|
+
def add_payment(post, payment)
|
134
|
+
card = {
|
135
|
+
expiryMonth: payment.month,
|
136
|
+
expiryYear: payment.year,
|
137
|
+
holderName: payment.name,
|
138
|
+
number: payment.number,
|
139
|
+
cvc: payment.verification_value
|
140
|
+
}
|
141
|
+
card.delete_if{|k,v| v.blank? }
|
142
|
+
requires!(card, :expiryMonth, :expiryYear, :holderName, :number, :cvc)
|
143
|
+
post[:card] = card
|
144
|
+
end
|
145
|
+
|
146
|
+
def add_references(post, authorization, options = {})
|
147
|
+
post[:originalReference] = authorization
|
148
|
+
post[:reference] = options[:reference]
|
149
|
+
end
|
150
|
+
|
151
|
+
def parse(body)
|
152
|
+
return {} if body.blank?
|
153
|
+
JSON.parse(body)
|
154
|
+
end
|
155
|
+
|
156
|
+
def commit(action, parameters)
|
157
|
+
url = (test? ? test_url : live_url)
|
158
|
+
|
159
|
+
begin
|
160
|
+
raw_response = ssl_post("#{url}/#{action.to_s}", post_data(action, parameters), request_headers)
|
161
|
+
response = parse(raw_response)
|
162
|
+
rescue ResponseError => e
|
163
|
+
raw_response = e.response.body
|
164
|
+
response = parse(raw_response)
|
165
|
+
end
|
166
|
+
|
167
|
+
success = success_from(action, response)
|
168
|
+
Response.new(
|
169
|
+
success,
|
170
|
+
message_from(action, response),
|
171
|
+
response,
|
172
|
+
authorization: authorization_from(response),
|
173
|
+
test: test?,
|
174
|
+
error_code: success ? nil : error_code_from(response)
|
175
|
+
)
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
def basic_auth
|
180
|
+
Base64.strict_encode64("#{@username}:#{@password}")
|
181
|
+
end
|
182
|
+
|
183
|
+
def request_headers
|
184
|
+
{
|
185
|
+
"Content-Type" => "application/json",
|
186
|
+
"Authorization" => "Basic #{basic_auth}"
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
190
|
+
def success_from(action, response)
|
191
|
+
case action.to_s
|
192
|
+
when 'authorise'
|
193
|
+
['Authorised', 'Received', 'RedirectShopper'].include?(response['resultCode'])
|
194
|
+
when 'capture', 'refund', 'cancel'
|
195
|
+
response['response'] == "[#{action}-received]"
|
196
|
+
else
|
197
|
+
false
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def message_from(action, response)
|
202
|
+
case action.to_s
|
203
|
+
when 'authorise'
|
204
|
+
response['refusalReason'] || response['resultCode'] || response['message']
|
205
|
+
when 'capture', 'refund', 'cancel'
|
206
|
+
response['response'] || response['message']
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def authorization_from(response)
|
211
|
+
response['pspReference']
|
212
|
+
end
|
213
|
+
|
214
|
+
def init_post(options = {})
|
215
|
+
{merchantAccount: options[:merchant_account] || @merchant_account}
|
216
|
+
end
|
217
|
+
|
218
|
+
def post_data(action, parameters = {})
|
219
|
+
JSON.generate(parameters)
|
220
|
+
end
|
221
|
+
|
222
|
+
def error_code_from(response)
|
223
|
+
STANDARD_ERROR_CODE_MAPPING[response['errorCode']]
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require 'nokogiri'
|
2
2
|
|
3
|
-
module ActiveMerchant
|
4
|
-
module Billing
|
3
|
+
module ActiveMerchant
|
4
|
+
module Billing
|
5
5
|
class AuthorizeNetGateway < Gateway
|
6
6
|
include Empty
|
7
7
|
|
8
8
|
self.test_url = 'https://apitest.authorize.net/xml/v1/request.api'
|
9
9
|
self.live_url = 'https://api2.authorize.net/xml/v1/request.api'
|
10
10
|
|
11
|
-
self.supported_countries = %w(AD AT AU BE BG CA CH CY CZ DE DK ES FI FR GB
|
11
|
+
self.supported_countries = %w(AD AT AU BE BG CA CH CY CZ DE DK EE ES FI FR GB GI GR HU IE IL IS IT LI LT LU LV MC MT NL NO PL PT RO SE SI SK SM TR US VA)
|
12
12
|
self.default_currency = 'USD'
|
13
13
|
self.money_format = :dollars
|
14
14
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro]
|
@@ -16,25 +16,45 @@ module ActiveMerchant #:nodoc:
|
|
16
16
|
self.homepage_url = 'http://www.authorize.net/'
|
17
17
|
self.display_name = 'Authorize.Net'
|
18
18
|
|
19
|
+
# Authorize.net has slightly different definitions for returned AVS codes
|
20
|
+
# that have been mapped to the closest equivalent AM standard AVSResult codes
|
21
|
+
# Authorize.net's descriptions noted below
|
22
|
+
STANDARD_AVS_CODE_MAPPING = {
|
23
|
+
'A' => 'A', # Street Address: Match -- First 5 Digits of ZIP: No Match
|
24
|
+
'B' => 'I', # Address not provided for AVS check or street address match, postal code could not be verified
|
25
|
+
'E' => 'E', # AVS Error
|
26
|
+
'G' => 'G', # Non U.S. Card Issuing Bank
|
27
|
+
'N' => 'N', # Street Address: No Match -- First 5 Digits of ZIP: No Match
|
28
|
+
'P' => 'I', # AVS not applicable for this transaction
|
29
|
+
'R' => 'R', # Retry, System Is Unavailable
|
30
|
+
'S' => 'S', # AVS Not Supported by Card Issuing Bank
|
31
|
+
'U' => 'U', # Address Information For This Cardholder Is Unavailable
|
32
|
+
'W' => 'W', # Street Address: No Match -- All 9 Digits of ZIP: Match
|
33
|
+
'X' => 'X', # Street Address: Match -- All 9 Digits of ZIP: Match
|
34
|
+
'Y' => 'Y', # Street Address: Match - First 5 Digits of ZIP: Match
|
35
|
+
'Z' => 'Z' # Street Address: No Match - First 5 Digits of ZIP: Match
|
36
|
+
}
|
37
|
+
|
19
38
|
STANDARD_ERROR_CODE_MAPPING = {
|
20
|
-
'36' => STANDARD_ERROR_CODE[:incorrect_number],
|
21
|
-
'237' => STANDARD_ERROR_CODE[:invalid_number],
|
22
|
-
'2315' => STANDARD_ERROR_CODE[:invalid_number],
|
23
|
-
'37' => STANDARD_ERROR_CODE[:invalid_expiry_date],
|
24
|
-
'2316' => STANDARD_ERROR_CODE[:invalid_expiry_date],
|
25
|
-
'378' => STANDARD_ERROR_CODE[:invalid_cvc],
|
26
|
-
'38' => STANDARD_ERROR_CODE[:expired_card],
|
27
|
-
'2317' => STANDARD_ERROR_CODE[:expired_card],
|
28
|
-
'244' => STANDARD_ERROR_CODE[:incorrect_cvc],
|
29
|
-
'227' => STANDARD_ERROR_CODE[:incorrect_address],
|
30
39
|
'2127' => STANDARD_ERROR_CODE[:incorrect_address],
|
31
40
|
'22' => STANDARD_ERROR_CODE[:card_declined],
|
41
|
+
'227' => STANDARD_ERROR_CODE[:incorrect_address],
|
32
42
|
'23' => STANDARD_ERROR_CODE[:card_declined],
|
33
|
-
'
|
43
|
+
'2315' => STANDARD_ERROR_CODE[:invalid_number],
|
44
|
+
'2316' => STANDARD_ERROR_CODE[:invalid_expiry_date],
|
45
|
+
'2317' => STANDARD_ERROR_CODE[:expired_card],
|
34
46
|
'235' => STANDARD_ERROR_CODE[:processing_error],
|
47
|
+
'237' => STANDARD_ERROR_CODE[:invalid_number],
|
35
48
|
'24' => STANDARD_ERROR_CODE[:pickup_card],
|
49
|
+
'244' => STANDARD_ERROR_CODE[:incorrect_cvc],
|
36
50
|
'300' => STANDARD_ERROR_CODE[:config_error],
|
37
|
-
'
|
51
|
+
'3153' => STANDARD_ERROR_CODE[:processing_error],
|
52
|
+
'3155' => STANDARD_ERROR_CODE[:unsupported_feature],
|
53
|
+
'36' => STANDARD_ERROR_CODE[:incorrect_number],
|
54
|
+
'37' => STANDARD_ERROR_CODE[:invalid_expiry_date],
|
55
|
+
'378' => STANDARD_ERROR_CODE[:invalid_cvc],
|
56
|
+
'38' => STANDARD_ERROR_CODE[:expired_card],
|
57
|
+
'384' => STANDARD_ERROR_CODE[:config_error],
|
38
58
|
}
|
39
59
|
|
40
60
|
MARKET_TYPE = {
|
@@ -61,7 +81,7 @@ module ActiveMerchant #:nodoc:
|
|
61
81
|
TRANSACTION_ALREADY_ACTIONED = %w(310 311)
|
62
82
|
|
63
83
|
CARD_CODE_ERRORS = %w(N S)
|
64
|
-
AVS_ERRORS = %w(A E N R W Z)
|
84
|
+
AVS_ERRORS = %w(A E I N R W Z)
|
65
85
|
AVS_REASON_CODES = %w(27 45)
|
66
86
|
|
67
87
|
TRACKS = {
|
@@ -72,6 +92,7 @@ module ActiveMerchant #:nodoc:
|
|
72
92
|
APPLE_PAY_DATA_DESCRIPTOR = "COMMON.APPLE.INAPP.PAYMENT"
|
73
93
|
|
74
94
|
PAYMENT_METHOD_NOT_SUPPORTED_ERROR = "155"
|
95
|
+
INELIGIBLE_FOR_ISSUING_CREDIT_ERROR = "54"
|
75
96
|
|
76
97
|
def initialize(options={})
|
77
98
|
requires!(options, :login, :password)
|
@@ -111,11 +132,18 @@ module ActiveMerchant #:nodoc:
|
|
111
132
|
end
|
112
133
|
|
113
134
|
def refund(amount, authorization, options={})
|
114
|
-
if auth_was_for_cim?(authorization)
|
135
|
+
response = if auth_was_for_cim?(authorization)
|
115
136
|
cim_refund(amount, authorization, options)
|
116
137
|
else
|
117
138
|
normal_refund(amount, authorization, options)
|
118
139
|
end
|
140
|
+
|
141
|
+
return response if response.success?
|
142
|
+
return response unless options[:force_full_refund_if_unsettled]
|
143
|
+
|
144
|
+
if response.params["response_reason_code"] == INELIGIBLE_FOR_ISSUING_CREDIT_ERROR
|
145
|
+
void(authorization, options)
|
146
|
+
end
|
119
147
|
end
|
120
148
|
|
121
149
|
def void(authorization, options={})
|
@@ -154,28 +182,24 @@ module ActiveMerchant #:nodoc:
|
|
154
182
|
end
|
155
183
|
|
156
184
|
def store(credit_card, options = {})
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
xml.email(options[:email]) unless empty?(options[:email])
|
162
|
-
|
163
|
-
xml.paymentProfiles do
|
164
|
-
xml.customerType("individual")
|
165
|
-
add_billing_address(xml, credit_card, options)
|
166
|
-
add_shipping_address(xml, options, "shipToList")
|
167
|
-
xml.payment do
|
168
|
-
xml.creditCard do
|
169
|
-
xml.cardNumber(truncate(credit_card.number, 16))
|
170
|
-
xml.expirationDate(format(credit_card.year, :four_digits) + '-' + format(credit_card.month, :two_digits))
|
171
|
-
xml.cardCode(credit_card.verification_value) if credit_card.verification_value
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
185
|
+
if options[:customer_profile_id]
|
186
|
+
create_customer_payment_profile(credit_card, options)
|
187
|
+
else
|
188
|
+
create_customer_profile(credit_card, options)
|
176
189
|
end
|
177
190
|
end
|
178
191
|
|
192
|
+
def unstore(authorization)
|
193
|
+
customer_profile_id, _, _ = split_authorization(authorization)
|
194
|
+
|
195
|
+
delete_customer_profile(customer_profile_id)
|
196
|
+
end
|
197
|
+
|
198
|
+
def verify_credentials
|
199
|
+
response = commit(:verify_credentials) { }
|
200
|
+
response.success?
|
201
|
+
end
|
202
|
+
|
179
203
|
def supports_scrubbing?
|
180
204
|
true
|
181
205
|
end
|
@@ -336,9 +360,13 @@ module ActiveMerchant #:nodoc:
|
|
336
360
|
end
|
337
361
|
end
|
338
362
|
|
363
|
+
def camel_case_lower(key)
|
364
|
+
String(key).split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
|
365
|
+
end
|
366
|
+
|
339
367
|
def add_settings(xml, source, options)
|
340
368
|
xml.transactionSettings do
|
341
|
-
if
|
369
|
+
if options[:recurring]
|
342
370
|
xml.setting do
|
343
371
|
xml.settingName("recurringBilling")
|
344
372
|
xml.settingValue("true")
|
@@ -356,6 +384,18 @@ module ActiveMerchant #:nodoc:
|
|
356
384
|
ActiveMerchant.deprecated "Using the duplicate_window class_attribute is deprecated. Use the transaction options hash instead."
|
357
385
|
set_duplicate_window(xml, self.class.duplicate_window)
|
358
386
|
end
|
387
|
+
if options[:email_customer]
|
388
|
+
xml.setting do
|
389
|
+
xml.settingName("emailCustomer")
|
390
|
+
xml.settingValue("true")
|
391
|
+
end
|
392
|
+
end
|
393
|
+
if options[:header_email_receipt]
|
394
|
+
xml.setting do
|
395
|
+
xml.settingName("headerEmailReceipt")
|
396
|
+
xml.settingValue(options[:header_email_receipt])
|
397
|
+
end
|
398
|
+
end
|
359
399
|
end
|
360
400
|
end
|
361
401
|
|
@@ -374,7 +414,7 @@ module ActiveMerchant #:nodoc:
|
|
374
414
|
xml.value(currency)
|
375
415
|
end
|
376
416
|
end
|
377
|
-
if application_id.present?
|
417
|
+
if application_id.present?
|
378
418
|
xml.userField do
|
379
419
|
xml.name("x_solution_id")
|
380
420
|
xml.value(application_id)
|
@@ -459,8 +499,7 @@ module ActiveMerchant #:nodoc:
|
|
459
499
|
xml.bankAccount do
|
460
500
|
xml.routingNumber(check.routing_number)
|
461
501
|
xml.accountNumber(check.account_number)
|
462
|
-
xml.nameOnAccount(check.name)
|
463
|
-
xml.echeckType("WEB")
|
502
|
+
xml.nameOnAccount(truncate(check.name, 22))
|
464
503
|
xml.bankName(check.bank_name)
|
465
504
|
xml.checkNumber(check.number)
|
466
505
|
end
|
@@ -536,6 +575,64 @@ module ActiveMerchant #:nodoc:
|
|
536
575
|
xml.invoiceNumber(truncate(options[:order_id], 20))
|
537
576
|
xml.description(truncate(options[:description], 255))
|
538
577
|
end
|
578
|
+
|
579
|
+
# Authorize.net API requires lineItems to be placed directly after order tag
|
580
|
+
if options[:line_items]
|
581
|
+
xml.lineItems do
|
582
|
+
options[:line_items].each do |line_item|
|
583
|
+
xml.lineItem do
|
584
|
+
line_item.each do |key, value|
|
585
|
+
xml.send(camel_case_lower(key), value)
|
586
|
+
end
|
587
|
+
end
|
588
|
+
end
|
589
|
+
end
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
def create_customer_payment_profile(credit_card, options)
|
594
|
+
commit(:cim_store_update) do |xml|
|
595
|
+
xml.customerProfileId options[:customer_profile_id]
|
596
|
+
xml.paymentProfile do
|
597
|
+
add_billing_address(xml, credit_card, options)
|
598
|
+
xml.payment do
|
599
|
+
xml.creditCard do
|
600
|
+
xml.cardNumber(truncate(credit_card.number, 16))
|
601
|
+
xml.expirationDate(format(credit_card.year, :four_digits) + '-' + format(credit_card.month, :two_digits))
|
602
|
+
xml.cardCode(credit_card.verification_value) if credit_card.verification_value
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
def create_customer_profile(credit_card, options)
|
610
|
+
commit(:cim_store) do |xml|
|
611
|
+
xml.profile do
|
612
|
+
xml.merchantCustomerId(truncate(options[:merchant_customer_id], 20) || SecureRandom.hex(10))
|
613
|
+
xml.description(truncate(options[:description], 255)) unless empty?(options[:description])
|
614
|
+
xml.email(options[:email]) unless empty?(options[:email])
|
615
|
+
|
616
|
+
xml.paymentProfiles do
|
617
|
+
xml.customerType("individual")
|
618
|
+
add_billing_address(xml, credit_card, options)
|
619
|
+
add_shipping_address(xml, options, "shipToList")
|
620
|
+
xml.payment do
|
621
|
+
xml.creditCard do
|
622
|
+
xml.cardNumber(truncate(credit_card.number, 16))
|
623
|
+
xml.expirationDate(format(credit_card.year, :four_digits) + '-' + format(credit_card.month, :two_digits))
|
624
|
+
xml.cardCode(credit_card.verification_value) if credit_card.verification_value
|
625
|
+
end
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
632
|
+
def delete_customer_profile(customer_profile_id)
|
633
|
+
commit(:cim_store_delete_customer) do |xml|
|
634
|
+
xml.customerProfileId(customer_profile_id)
|
635
|
+
end
|
539
636
|
end
|
540
637
|
|
541
638
|
def names_from(payment_source, address, options)
|
@@ -556,7 +653,7 @@ module ActiveMerchant #:nodoc:
|
|
556
653
|
end
|
557
654
|
|
558
655
|
def parse(action, raw_response)
|
559
|
-
if is_cim_action?(action)
|
656
|
+
if is_cim_action?(action) || action == :verify_credentials
|
560
657
|
parse_cim(raw_response)
|
561
658
|
else
|
562
659
|
parse_normal(action, raw_response)
|
@@ -567,7 +664,8 @@ module ActiveMerchant #:nodoc:
|
|
567
664
|
raw_response = ssl_post(url, post_data(action, &payload), headers)
|
568
665
|
response = parse(action, raw_response)
|
569
666
|
|
570
|
-
|
667
|
+
avs_result_code = response[:avs_result_code].upcase if response[:avs_result_code]
|
668
|
+
avs_result = AVSResult.new(code: STANDARD_AVS_CODE_MAPPING[avs_result_code])
|
571
669
|
cvv_result = CVVResult.new(response[:card_code])
|
572
670
|
if using_live_gateway_in_test_mode?(response)
|
573
671
|
Response.new(false, "Using a live Authorize.net account in Test Mode is not permitted.")
|
@@ -602,6 +700,12 @@ module ActiveMerchant #:nodoc:
|
|
602
700
|
def root_for(action)
|
603
701
|
if action == :cim_store
|
604
702
|
"createCustomerProfileRequest"
|
703
|
+
elsif action == :cim_store_update
|
704
|
+
"createCustomerPaymentProfileRequest"
|
705
|
+
elsif action == :cim_store_delete_customer
|
706
|
+
"deleteCustomerProfileRequest"
|
707
|
+
elsif action == :verify_credentials
|
708
|
+
"authenticateTestRequest"
|
605
709
|
elsif is_cim_action?(action)
|
606
710
|
"createCustomerProfileTransactionRequest"
|
607
711
|
else
|
@@ -697,6 +801,11 @@ module ActiveMerchant #:nodoc:
|
|
697
801
|
(empty?(element.content) ? nil : element.content)
|
698
802
|
end
|
699
803
|
|
804
|
+
response[:customer_payment_profile_id] = if(element = doc.at_xpath("//customerPaymentProfileIdList/numericString") ||
|
805
|
+
doc.at_xpath("//customerPaymentProfileId"))
|
806
|
+
(empty?(element.content) ? nil : element.content)
|
807
|
+
end
|
808
|
+
|
700
809
|
response[:direct_response] = if(element = doc.at_xpath("//directResponse"))
|
701
810
|
(empty?(element.content) ? nil : element.content)
|
702
811
|
end
|
@@ -707,7 +816,7 @@ module ActiveMerchant #:nodoc:
|
|
707
816
|
end
|
708
817
|
|
709
818
|
def success_from(action, response)
|
710
|
-
if action == :
|
819
|
+
if cim?(action) || (action == :verify_credentials)
|
711
820
|
response[:result_code] == "Ok"
|
712
821
|
else
|
713
822
|
response[:response_code] == APPROVED && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code])
|
@@ -727,7 +836,7 @@ module ActiveMerchant #:nodoc:
|
|
727
836
|
end
|
728
837
|
|
729
838
|
def authorization_from(action, response)
|
730
|
-
if action
|
839
|
+
if cim?(action)
|
731
840
|
[response[:customer_profile_id], response[:customer_payment_profile_id], action].join("#")
|
732
841
|
else
|
733
842
|
[response[:transaction_id], response[:account_number], action].join("#")
|
@@ -738,6 +847,10 @@ module ActiveMerchant #:nodoc:
|
|
738
847
|
authorization.split("#")
|
739
848
|
end
|
740
849
|
|
850
|
+
def cim?(action)
|
851
|
+
(action == :cim_store) || (action == :cim_store_update) || (action == :cim_store_delete_customer)
|
852
|
+
end
|
853
|
+
|
741
854
|
def transaction_id_from(authorization)
|
742
855
|
transaction_id, _, _ = split_authorization(authorization)
|
743
856
|
transaction_id
|
@@ -574,6 +574,7 @@ module ActiveMerchant #:nodoc:
|
|
574
574
|
def build_get_customer_payment_profile_request(xml, options)
|
575
575
|
xml.tag!('customerProfileId', options[:customer_profile_id])
|
576
576
|
xml.tag!('customerPaymentProfileId', options[:customer_payment_profile_id])
|
577
|
+
xml.tag!('unmaskExpirationDate', options[:unmask_expiration_date]) if options[:unmask_expiration_date]
|
577
578
|
xml.target!
|
578
579
|
end
|
579
580
|
|
@@ -863,10 +864,12 @@ module ActiveMerchant #:nodoc:
|
|
863
864
|
response_params['direct_response'] = parse_direct_response(response_params['direct_response']) if response_params['direct_response']
|
864
865
|
transaction_id = response_params['direct_response']['transaction_id'] if response_params['direct_response']
|
865
866
|
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
867
|
+
response_options = {}
|
868
|
+
response_options[:test] = test_mode
|
869
|
+
response_options[:authorization] = transaction_id || response_params['customer_profile_id'] || (response_params['profile'] ? response_params['profile']['customer_profile_id'] : nil)
|
870
|
+
response_options[:error_code] = response_params['messages']['message']['code'] unless success
|
871
|
+
|
872
|
+
Response.new(success, message, response_params, response_options)
|
870
873
|
end
|
871
874
|
|
872
875
|
def tag_unless_blank(xml, tag_name, data)
|