activemerchant 1.90.0 → 1.99.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.
- checksums.yaml +4 -4
- data/CHANGELOG +202 -0
- data/README.md +6 -2
- data/lib/active_merchant/billing/avs_result.rb +4 -5
- data/lib/active_merchant/billing/credit_card.rb +8 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +81 -5
- data/lib/active_merchant/billing/gateway.rb +10 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +206 -54
- data/lib/active_merchant/billing/gateways/bambora_apac.rb +226 -0
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -10
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +3 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +11 -6
- data/lib/active_merchant/billing/gateways/blue_pay.rb +10 -8
- data/lib/active_merchant/billing/gateways/blue_snap.rb +211 -36
- data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +79 -18
- data/lib/active_merchant/billing/gateways/card_connect.rb +6 -1
- data/lib/active_merchant/billing/gateways/cecabank.rb +20 -9
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +98 -61
- data/lib/active_merchant/billing/gateways/credorax.rb +69 -4
- data/lib/active_merchant/billing/gateways/cyber_source.rb +85 -14
- data/lib/active_merchant/billing/gateways/d_local.rb +3 -3
- data/lib/active_merchant/billing/gateways/decidir.rb +245 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +9 -0
- data/lib/active_merchant/billing/gateways/epay.rb +13 -2
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +42 -12
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +26 -7
- data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +42 -3
- data/lib/active_merchant/billing/gateways/global_collect.rb +3 -7
- data/lib/active_merchant/billing/gateways/hps.rb +46 -1
- data/lib/active_merchant/billing/gateways/ipp.rb +1 -0
- data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
- data/lib/active_merchant/billing/gateways/litle.rb +61 -3
- data/lib/active_merchant/billing/gateways/mastercard.rb +30 -5
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -1
- data/lib/active_merchant/billing/gateways/migs.rb +8 -0
- data/lib/active_merchant/billing/gateways/monei.rb +31 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +3 -4
- data/lib/active_merchant/billing/gateways/mundipagg.rb +37 -9
- data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
- data/lib/active_merchant/billing/gateways/netbanx.rb +4 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +45 -5
- data/lib/active_merchant/billing/gateways/openpay.rb +1 -1
- data/lib/active_merchant/billing/gateways/opp.rb +20 -1
- data/lib/active_merchant/billing/gateways/orbital.rb +92 -11
- data/lib/active_merchant/billing/gateways/payflow.rb +64 -14
- data/lib/active_merchant/billing/gateways/payment_express.rb +7 -0
- data/lib/active_merchant/billing/gateways/paymentez.rb +7 -11
- data/lib/active_merchant/billing/gateways/paymill.rb +5 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
- data/lib/active_merchant/billing/gateways/paypal_express.rb +3 -1
- data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -2
- data/lib/active_merchant/billing/gateways/pin.rb +19 -6
- data/lib/active_merchant/billing/gateways/pro_pay.rb +1 -1
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -1
- data/lib/active_merchant/billing/gateways/qvalent.rb +54 -1
- data/lib/active_merchant/billing/gateways/realex.rb +42 -5
- data/lib/active_merchant/billing/gateways/redsys.rb +113 -30
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
- data/lib/active_merchant/billing/gateways/stripe.rb +66 -34
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +271 -0
- data/lib/active_merchant/billing/gateways/tns.rb +10 -5
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +5 -5
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +46 -6
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +19 -8
- data/lib/active_merchant/billing/gateways/visanet_peru.rb +22 -10
- data/lib/active_merchant/billing/gateways/worldpay.rb +237 -34
- data/lib/active_merchant/country.rb +2 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +20 -4
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
require 'active_support/core_ext/hash/slice'
|
|
2
|
+
|
|
3
|
+
module ActiveMerchant #:nodoc:
|
|
4
|
+
module Billing #:nodoc:
|
|
5
|
+
# This gateway uses the current Stripe {Payment Intents API}[https://stripe.com/docs/api/payment_intents].
|
|
6
|
+
# For the legacy API, see the Stripe gateway
|
|
7
|
+
class StripePaymentIntentsGateway < StripeGateway
|
|
8
|
+
|
|
9
|
+
self.supported_countries = %w(AT AU BE BR CA CH DE DK EE ES FI FR GB GR HK IE IT JP LT LU LV MX NL NO NZ PL PT SE SG SI SK US)
|
|
10
|
+
|
|
11
|
+
ALLOWED_METHOD_STATES = %w[automatic manual].freeze
|
|
12
|
+
ALLOWED_CANCELLATION_REASONS = %w[duplicate fraudulent requested_by_customer abandoned].freeze
|
|
13
|
+
CREATE_INTENT_ATTRIBUTES = %i[description statement_descriptor receipt_email save_payment_method]
|
|
14
|
+
CONFIRM_INTENT_ATTRIBUTES = %i[receipt_email return_url save_payment_method setup_future_usage off_session]
|
|
15
|
+
UPDATE_INTENT_ATTRIBUTES = %i[description statement_descriptor receipt_email setup_future_usage]
|
|
16
|
+
DEFAULT_API_VERSION = '2019-05-16'
|
|
17
|
+
|
|
18
|
+
def create_intent(money, payment_method, options = {})
|
|
19
|
+
post = {}
|
|
20
|
+
add_amount(post, money, options, true)
|
|
21
|
+
add_capture_method(post, options)
|
|
22
|
+
add_confirmation_method(post, options)
|
|
23
|
+
add_customer(post, options)
|
|
24
|
+
add_payment_method_token(post, payment_method, options)
|
|
25
|
+
add_metadata(post, options)
|
|
26
|
+
add_return_url(post, options)
|
|
27
|
+
add_connected_account(post, options)
|
|
28
|
+
add_shipping_address(post, options)
|
|
29
|
+
setup_future_usage(post, options)
|
|
30
|
+
add_exemption(post, options)
|
|
31
|
+
|
|
32
|
+
CREATE_INTENT_ATTRIBUTES.each do |attribute|
|
|
33
|
+
add_whitelisted_attribute(post, options, attribute)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
commit(:post, 'payment_intents', post, options)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def show_intent(intent_id, options)
|
|
40
|
+
commit(:get, "payment_intents/#{intent_id}", nil, options)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def confirm_intent(intent_id, payment_method, options = {})
|
|
44
|
+
post = {}
|
|
45
|
+
add_payment_method_token(post, payment_method, options)
|
|
46
|
+
CONFIRM_INTENT_ATTRIBUTES.each do |attribute|
|
|
47
|
+
add_whitelisted_attribute(post, options, attribute)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
commit(:post, "payment_intents/#{intent_id}/confirm", post, options)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def create_payment_method(payment_method, options = {})
|
|
54
|
+
post = {}
|
|
55
|
+
post[:type] = 'card'
|
|
56
|
+
post[:card] = {}
|
|
57
|
+
post[:card][:number] = payment_method.number
|
|
58
|
+
post[:card][:exp_month] = payment_method.month
|
|
59
|
+
post[:card][:exp_year] = payment_method.year
|
|
60
|
+
post[:card][:cvc] = payment_method.verification_value if payment_method.verification_value
|
|
61
|
+
add_billing_address(post, options)
|
|
62
|
+
|
|
63
|
+
commit(:post, 'payment_methods', post, options)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def update_intent(money, intent_id, payment_method, options = {})
|
|
67
|
+
post = {}
|
|
68
|
+
post[:amount] = money if money
|
|
69
|
+
|
|
70
|
+
add_payment_method_token(post, payment_method, options)
|
|
71
|
+
add_payment_method_types(post, options)
|
|
72
|
+
add_customer(post, options)
|
|
73
|
+
add_metadata(post, options)
|
|
74
|
+
add_shipping_address(post, options)
|
|
75
|
+
add_connected_account(post, options)
|
|
76
|
+
|
|
77
|
+
UPDATE_INTENT_ATTRIBUTES.each do |attribute|
|
|
78
|
+
add_whitelisted_attribute(post, options, attribute)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
commit(:post, "payment_intents/#{intent_id}", post, options)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def authorize(money, payment_method, options = {})
|
|
85
|
+
create_intent(money, payment_method, options.merge!(confirm: true, capture_method: 'manual'))
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def purchase(money, payment_method, options = {})
|
|
89
|
+
create_intent(money, payment_method, options.merge!(confirm: true, capture_method: 'automatic'))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def capture(money, intent_id, options = {})
|
|
93
|
+
post = {}
|
|
94
|
+
post[:amount_to_capture] = money
|
|
95
|
+
if options[:transfer_amount]
|
|
96
|
+
post[:transfer_data] = {}
|
|
97
|
+
post[:transfer_data][:amount] = options[:transfer_amount]
|
|
98
|
+
end
|
|
99
|
+
post[:application_fee_amount] = options[:application_fee] if options[:application_fee]
|
|
100
|
+
commit(:post, "payment_intents/#{intent_id}/capture", post, options)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def void(intent_id, options = {})
|
|
104
|
+
post = {}
|
|
105
|
+
post[:cancellation_reason] = options[:cancellation_reason] if ALLOWED_CANCELLATION_REASONS.include?(options[:cancellation_reason])
|
|
106
|
+
commit(:post, "payment_intents/#{intent_id}/cancel", post, options)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def refund(money, intent_id, options = {})
|
|
110
|
+
intent = commit(:get, "payment_intents/#{intent_id}", nil, options)
|
|
111
|
+
charge_id = intent.params.dig('charges', 'data')[0].dig('id')
|
|
112
|
+
super(money, charge_id, options)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Note: Not all payment methods are currently supported by the {Payment Methods API}[https://stripe.com/docs/payments/payment-methods]
|
|
116
|
+
# Current implementation will create a PaymentMethod object if the method is a token or credit card
|
|
117
|
+
# All other types will default to legacy Stripe store
|
|
118
|
+
def store(payment_method, options = {})
|
|
119
|
+
params = {}
|
|
120
|
+
post = {}
|
|
121
|
+
|
|
122
|
+
# If customer option is provided, create a payment method and attach to customer id
|
|
123
|
+
# Otherwise, create a customer, then attach
|
|
124
|
+
if payment_method.is_a?(StripePaymentToken) || payment_method.is_a?(ActiveMerchant::Billing::CreditCard)
|
|
125
|
+
add_payment_method_token(params, payment_method, options)
|
|
126
|
+
if options[:customer]
|
|
127
|
+
customer_id = options[:customer]
|
|
128
|
+
else
|
|
129
|
+
post[:validate] = options[:validate] unless options[:validate].nil?
|
|
130
|
+
post[:description] = options[:description] if options[:description]
|
|
131
|
+
post[:email] = options[:email] if options[:email]
|
|
132
|
+
customer = commit(:post, 'customers', post, options)
|
|
133
|
+
customer_id = customer.params['id']
|
|
134
|
+
end
|
|
135
|
+
commit(:post, "payment_methods/#{params[:payment_method]}/attach", { customer: customer_id }, options)
|
|
136
|
+
else
|
|
137
|
+
super(payment, options)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def unstore(identification, options = {}, deprecated_options = {})
|
|
142
|
+
if identification.include?('pm_')
|
|
143
|
+
_, payment_method = identification.split('|')
|
|
144
|
+
commit(:post, "payment_methods/#{payment_method}/detach", nil, options)
|
|
145
|
+
else
|
|
146
|
+
super(identification, options, deprecated_options)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
private
|
|
151
|
+
|
|
152
|
+
def add_whitelisted_attribute(post, options, attribute)
|
|
153
|
+
post[attribute] = options[attribute] if options[attribute]
|
|
154
|
+
post
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def add_capture_method(post, options)
|
|
158
|
+
capture_method = options[:capture_method].to_s
|
|
159
|
+
post[:capture_method] = capture_method if ALLOWED_METHOD_STATES.include?(capture_method)
|
|
160
|
+
post
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def add_confirmation_method(post, options)
|
|
164
|
+
confirmation_method = options[:confirmation_method].to_s
|
|
165
|
+
post[:confirmation_method] = confirmation_method if ALLOWED_METHOD_STATES.include?(confirmation_method)
|
|
166
|
+
post
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def add_customer(post, options)
|
|
170
|
+
customer = options[:customer].to_s
|
|
171
|
+
post[:customer] = customer if customer.start_with?('cus_')
|
|
172
|
+
post
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def add_return_url(post, options)
|
|
176
|
+
return unless options[:confirm]
|
|
177
|
+
post[:confirm] = options[:confirm]
|
|
178
|
+
post[:return_url] = options[:return_url] if options[:return_url]
|
|
179
|
+
post
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def add_payment_method_token(post, payment_method, options)
|
|
183
|
+
return if payment_method.nil?
|
|
184
|
+
|
|
185
|
+
if payment_method.is_a?(ActiveMerchant::Billing::CreditCard)
|
|
186
|
+
p = create_payment_method(payment_method, options)
|
|
187
|
+
payment_method = p.params['id']
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
if payment_method.is_a?(StripePaymentToken)
|
|
191
|
+
post[:payment_method] = payment_method.payment_data['id']
|
|
192
|
+
elsif payment_method.is_a?(String)
|
|
193
|
+
if payment_method.include?('|')
|
|
194
|
+
customer_id, payment_method_id = payment_method.split('|')
|
|
195
|
+
token = payment_method_id
|
|
196
|
+
post[:customer] = customer_id
|
|
197
|
+
else
|
|
198
|
+
token = payment_method
|
|
199
|
+
end
|
|
200
|
+
post[:payment_method] = token
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def add_payment_method_types(post, options)
|
|
205
|
+
payment_method_types = options[:payment_method_types] if options[:payment_method_types]
|
|
206
|
+
return if payment_method_types.nil?
|
|
207
|
+
|
|
208
|
+
post[:payment_method_types] = Array(payment_method_types)
|
|
209
|
+
post
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def add_exemption(post, options = {})
|
|
213
|
+
return unless options[:confirm]
|
|
214
|
+
post[:payment_method_options] ||= {}
|
|
215
|
+
post[:payment_method_options][:card] ||= {}
|
|
216
|
+
post[:payment_method_options][:card][:moto] = true if options[:moto]
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def setup_future_usage(post, options = {})
|
|
220
|
+
post[:setup_future_usage] = options[:setup_future_usage] if %w( on_session off_session ).include?(options[:setup_future_usage])
|
|
221
|
+
post[:off_session] = options[:off_session] if options[:off_session] && options[:confirm] == true
|
|
222
|
+
post
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def add_connected_account(post, options = {})
|
|
226
|
+
return unless options[:transfer_destination]
|
|
227
|
+
post[:transfer_data] = {}
|
|
228
|
+
post[:transfer_data][:destination] = options[:transfer_destination]
|
|
229
|
+
post[:transfer_data][:amount] = options[:transfer_amount] if options[:transfer_amount]
|
|
230
|
+
post[:on_behalf_of] = options[:on_behalf_of] if options[:on_behalf_of]
|
|
231
|
+
post[:transfer_group] = options[:transfer_group] if options[:transfer_group]
|
|
232
|
+
post[:application_fee_amount] = options[:application_fee] if options[:application_fee]
|
|
233
|
+
post
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def add_billing_address(post, options = {})
|
|
237
|
+
return unless billing = options[:billing_address] || options[:address]
|
|
238
|
+
post[:billing_details] = {}
|
|
239
|
+
post[:billing_details][:address] = {}
|
|
240
|
+
post[:billing_details][:address][:city] = billing[:city] if billing[:city]
|
|
241
|
+
post[:billing_details][:address][:country] = billing[:country] if billing[:country]
|
|
242
|
+
post[:billing_details][:address][:line1] = billing[:address1] if billing[:address1]
|
|
243
|
+
post[:billing_details][:address][:line2] = billing[:address2] if billing[:address2]
|
|
244
|
+
post[:billing_details][:address][:postal_code] = billing[:zip] if billing[:zip]
|
|
245
|
+
post[:billing_details][:address][:state] = billing[:state] if billing[:state]
|
|
246
|
+
post[:billing_details][:email] = billing[:email] if billing[:email]
|
|
247
|
+
post[:billing_details][:name] = billing[:name] if billing[:name]
|
|
248
|
+
post[:billing_details][:phone] = billing[:phone] if billing[:phone]
|
|
249
|
+
post
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def add_shipping_address(post, options = {})
|
|
253
|
+
return unless shipping = options[:shipping]
|
|
254
|
+
post[:shipping] = {}
|
|
255
|
+
post[:shipping][:address] = {}
|
|
256
|
+
post[:shipping][:address][:line1] = shipping[:address][:line1]
|
|
257
|
+
post[:shipping][:address][:city] = shipping[:address][:city] if shipping[:address][:city]
|
|
258
|
+
post[:shipping][:address][:country] = shipping[:address][:country] if shipping[:address][:country]
|
|
259
|
+
post[:shipping][:address][:line2] = shipping[:address][:line2] if shipping[:address][:line2]
|
|
260
|
+
post[:shipping][:address][:postal_code] = shipping[:address][:postal_code] if shipping[:address][:postal_code]
|
|
261
|
+
post[:shipping][:address][:state] = shipping[:address][:state] if shipping[:address][:state]
|
|
262
|
+
|
|
263
|
+
post[:shipping][:name] = shipping[:name]
|
|
264
|
+
post[:shipping][:carrier] = shipping[:carrier] if shipping[:carrier]
|
|
265
|
+
post[:shipping][:phone] = shipping[:phone] if shipping[:phone]
|
|
266
|
+
post[:shipping][:tracking_number] = shipping[:tracking_number] if shipping[:tracking_number]
|
|
267
|
+
post
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
@@ -3,13 +3,18 @@ module ActiveMerchant
|
|
|
3
3
|
class TnsGateway < Gateway
|
|
4
4
|
include MastercardGateway
|
|
5
5
|
|
|
6
|
-
class_attribute :live_na_url, :live_ap_url, :test_na_url, :test_ap_url
|
|
6
|
+
class_attribute :live_na_url, :live_ap_url, :live_eu_url, :test_na_url, :test_ap_url, :test_eu_url
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
self.test_na_url = 'https://secure.na.tnspayments.com/api/rest/version/36/'
|
|
8
|
+
VERSION = '52'
|
|
10
9
|
|
|
11
|
-
self.
|
|
12
|
-
self.
|
|
10
|
+
self.live_na_url = "https://secure.na.tnspayments.com/api/rest/version/#{VERSION}/"
|
|
11
|
+
self.test_na_url = "https://secure.na.tnspayments.com/api/rest/version/#{VERSION}/"
|
|
12
|
+
|
|
13
|
+
self.live_ap_url = "https://secure.ap.tnspayments.com/api/rest/version/#{VERSION}/"
|
|
14
|
+
self.test_ap_url = "https://secure.ap.tnspayments.com/api/rest/version/#{VERSION}/"
|
|
15
|
+
|
|
16
|
+
self.live_eu_url = "https://secure.eu.tnspayments.com/api/rest/version/#{VERSION}/"
|
|
17
|
+
self.test_eu_url = "https://secure.eu.tnspayments.com/api/rest/version/#{VERSION}/"
|
|
13
18
|
|
|
14
19
|
self.display_name = 'TNS'
|
|
15
20
|
self.homepage_url = 'http://www.tnsi.com/'
|
|
@@ -532,7 +532,7 @@ module ActiveMerchant #:nodoc:
|
|
|
532
532
|
|
|
533
533
|
def add_contact(doc, fullname, options)
|
|
534
534
|
doc['v1'].contact do
|
|
535
|
-
doc['v1'].fullName fullname
|
|
535
|
+
doc['v1'].fullName fullname unless fullname.blank?
|
|
536
536
|
doc['v1'].coName options[:company_name] if options[:company_name]
|
|
537
537
|
doc['v1'].title options[:title] if options[:title]
|
|
538
538
|
|
|
@@ -544,7 +544,7 @@ module ActiveMerchant #:nodoc:
|
|
|
544
544
|
end
|
|
545
545
|
end
|
|
546
546
|
doc['v1'].addrLn1 billing_address[:address1] if billing_address[:address1]
|
|
547
|
-
doc['v1'].addrLn2 billing_address[:address2]
|
|
547
|
+
doc['v1'].addrLn2 billing_address[:address2] unless billing_address[:address2].blank?
|
|
548
548
|
doc['v1'].city billing_address[:city] if billing_address[:city]
|
|
549
549
|
doc['v1'].state billing_address[:state] if billing_address[:state]
|
|
550
550
|
doc['v1'].zipCode billing_address[:zip] if billing_address[:zip]
|
|
@@ -557,9 +557,9 @@ module ActiveMerchant #:nodoc:
|
|
|
557
557
|
|
|
558
558
|
if (shipping_address = options[:shipping_address])
|
|
559
559
|
doc['v1'].ship do
|
|
560
|
-
doc['v1'].fullName fullname
|
|
560
|
+
doc['v1'].fullName fullname unless fullname.blank?
|
|
561
561
|
doc['v1'].addrLn1 shipping_address[:address1] if shipping_address[:address1]
|
|
562
|
-
doc['v1'].addrLn2 shipping_address[:address2]
|
|
562
|
+
doc['v1'].addrLn2 shipping_address[:address2] unless shipping_address[:address2].blank?
|
|
563
563
|
doc['v1'].city shipping_address[:city] if shipping_address[:city]
|
|
564
564
|
doc['v1'].state shipping_address[:state] if shipping_address[:state]
|
|
565
565
|
doc['v1'].zipCode shipping_address[:zip] if shipping_address[:zip]
|
|
@@ -572,7 +572,7 @@ module ActiveMerchant #:nodoc:
|
|
|
572
572
|
|
|
573
573
|
def add_name(doc, payment_method)
|
|
574
574
|
doc['v1'].contact do
|
|
575
|
-
doc['v1'].fullName payment_method.name
|
|
575
|
+
doc['v1'].fullName payment_method.name unless payment_method.name.blank?
|
|
576
576
|
end
|
|
577
577
|
end
|
|
578
578
|
|
|
@@ -104,6 +104,8 @@ module ActiveMerchant #:nodoc:
|
|
|
104
104
|
TEST_LOGIN = 'TestMerchant'
|
|
105
105
|
TEST_PASSWORD = 'password'
|
|
106
106
|
|
|
107
|
+
VOIDABLE_ACTIONS = %w(preauth sale postauth credit)
|
|
108
|
+
|
|
107
109
|
self.money_format = :cents
|
|
108
110
|
self.supported_cardtypes = [:visa, :master, :discover, :american_express, :diners_club, :jcb]
|
|
109
111
|
self.supported_countries = ['US']
|
|
@@ -157,6 +159,8 @@ module ActiveMerchant #:nodoc:
|
|
|
157
159
|
add_customer_data(parameters, options)
|
|
158
160
|
add_payment_source(parameters, creditcard_or_billing_id)
|
|
159
161
|
add_addresses(parameters, options)
|
|
162
|
+
add_custom_fields(parameters, options)
|
|
163
|
+
|
|
160
164
|
commit('preauth', parameters)
|
|
161
165
|
end
|
|
162
166
|
|
|
@@ -172,6 +176,8 @@ module ActiveMerchant #:nodoc:
|
|
|
172
176
|
add_customer_data(parameters, options)
|
|
173
177
|
add_payment_source(parameters, creditcard_or_billing_id)
|
|
174
178
|
add_addresses(parameters, options)
|
|
179
|
+
add_custom_fields(parameters, options)
|
|
180
|
+
|
|
175
181
|
commit('sale', parameters)
|
|
176
182
|
end
|
|
177
183
|
|
|
@@ -179,11 +185,13 @@ module ActiveMerchant #:nodoc:
|
|
|
179
185
|
# postauth, we preserve active_merchant's nomenclature of capture() for consistency with the rest of the library. To process
|
|
180
186
|
# a postauthorization with TC, you need an amount in cents or a money object, and a TC transid.
|
|
181
187
|
def capture(money, authorization, options = {})
|
|
188
|
+
transaction_id, _ = split_authorization(authorization)
|
|
182
189
|
parameters = {
|
|
183
190
|
:amount => amount(money),
|
|
184
|
-
:transid =>
|
|
191
|
+
:transid => transaction_id,
|
|
185
192
|
}
|
|
186
193
|
add_aggregator(parameters, options)
|
|
194
|
+
add_custom_fields(parameters, options)
|
|
187
195
|
|
|
188
196
|
commit('postauth', parameters)
|
|
189
197
|
end
|
|
@@ -191,11 +199,15 @@ module ActiveMerchant #:nodoc:
|
|
|
191
199
|
# refund() allows you to return money to a card that was previously billed. You need to supply the amount, in cents or a money object,
|
|
192
200
|
# that you want to refund, and a TC transid for the transaction that you are refunding.
|
|
193
201
|
def refund(money, identification, options = {})
|
|
202
|
+
transaction_id, _ = split_authorization(identification)
|
|
203
|
+
|
|
194
204
|
parameters = {
|
|
195
205
|
:amount => amount(money),
|
|
196
|
-
:transid =>
|
|
206
|
+
:transid => transaction_id
|
|
197
207
|
}
|
|
208
|
+
|
|
198
209
|
add_aggregator(parameters, options)
|
|
210
|
+
add_custom_fields(parameters, options)
|
|
199
211
|
|
|
200
212
|
commit('credit', parameters)
|
|
201
213
|
end
|
|
@@ -214,18 +226,26 @@ module ActiveMerchant #:nodoc:
|
|
|
214
226
|
# TrustCommerce to allow for reversal transactions before you can use this
|
|
215
227
|
# method.
|
|
216
228
|
#
|
|
229
|
+
# void() is also used to to cancel a capture (postauth), purchase (sale),
|
|
230
|
+
# or refund (credit) or a before it is sent for settlement.
|
|
231
|
+
#
|
|
217
232
|
# NOTE: AMEX preauth's cannot be reversed. If you want to clear it more
|
|
218
233
|
# quickly than the automatic expiration (7-10 days), you will have to
|
|
219
234
|
# capture it and then immediately issue a credit for the same amount
|
|
220
235
|
# which should clear the customers credit card with 48 hours according to
|
|
221
236
|
# TC.
|
|
222
237
|
def void(authorization, options = {})
|
|
238
|
+
transaction_id, original_action = split_authorization(authorization)
|
|
239
|
+
action = (VOIDABLE_ACTIONS - ['preauth']).include?(original_action) ? 'void' : 'reversal'
|
|
240
|
+
|
|
223
241
|
parameters = {
|
|
224
|
-
:transid =>
|
|
242
|
+
:transid => transaction_id,
|
|
225
243
|
}
|
|
244
|
+
|
|
226
245
|
add_aggregator(parameters, options)
|
|
246
|
+
add_custom_fields(parameters, options)
|
|
227
247
|
|
|
228
|
-
commit(
|
|
248
|
+
commit(action, parameters)
|
|
229
249
|
end
|
|
230
250
|
|
|
231
251
|
# recurring() a TrustCommerce account that is activated for Citadel, TrustCommerce's
|
|
@@ -284,6 +304,8 @@ module ActiveMerchant #:nodoc:
|
|
|
284
304
|
|
|
285
305
|
add_creditcard(parameters, creditcard)
|
|
286
306
|
add_addresses(parameters, options)
|
|
307
|
+
add_custom_fields(parameters, options)
|
|
308
|
+
|
|
287
309
|
commit('store', parameters)
|
|
288
310
|
end
|
|
289
311
|
|
|
@@ -294,6 +316,8 @@ module ActiveMerchant #:nodoc:
|
|
|
294
316
|
:billingid => identification,
|
|
295
317
|
}
|
|
296
318
|
|
|
319
|
+
add_custom_fields(parameters, options)
|
|
320
|
+
|
|
297
321
|
commit('unstore', parameters)
|
|
298
322
|
end
|
|
299
323
|
|
|
@@ -311,6 +335,12 @@ module ActiveMerchant #:nodoc:
|
|
|
311
335
|
|
|
312
336
|
private
|
|
313
337
|
|
|
338
|
+
def add_custom_fields(params, options)
|
|
339
|
+
options[:custom_fields]&.each do |key, value|
|
|
340
|
+
params[key.to_sym] = value
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
314
344
|
def add_aggregator(params, options)
|
|
315
345
|
if @options[:aggregator_id] || application_id != Gateway.application_id
|
|
316
346
|
params[:aggregators] = 1
|
|
@@ -333,6 +363,7 @@ module ActiveMerchant #:nodoc:
|
|
|
333
363
|
params[:routing] = check.routing_number
|
|
334
364
|
params[:account] = check.account_number
|
|
335
365
|
params[:savings] = 'y' if check.account_type == 'savings'
|
|
366
|
+
params[:name] = check.name
|
|
336
367
|
end
|
|
337
368
|
|
|
338
369
|
def add_creditcard(params, creditcard)
|
|
@@ -408,14 +439,14 @@ module ActiveMerchant #:nodoc:
|
|
|
408
439
|
TCLink.send(parameters)
|
|
409
440
|
else
|
|
410
441
|
parse(ssl_post(self.live_url, post_data(parameters)))
|
|
411
|
-
|
|
442
|
+
end
|
|
412
443
|
|
|
413
444
|
# to be considered successful, transaction status must be either "approved" or "accepted"
|
|
414
445
|
success = SUCCESS_TYPES.include?(data['status'])
|
|
415
446
|
message = message_from(data)
|
|
416
447
|
Response.new(success, message, data,
|
|
417
448
|
:test => test?,
|
|
418
|
-
:authorization => data
|
|
449
|
+
:authorization => authorization_from(action, data),
|
|
419
450
|
:cvv_result => data['cvv'],
|
|
420
451
|
:avs_result => { :code => data['avs'] }
|
|
421
452
|
)
|
|
@@ -445,6 +476,15 @@ module ActiveMerchant #:nodoc:
|
|
|
445
476
|
end
|
|
446
477
|
end
|
|
447
478
|
|
|
479
|
+
def authorization_from(action, data)
|
|
480
|
+
authorization = data['transid']
|
|
481
|
+
authorization = "#{authorization}|#{action}" if authorization && VOIDABLE_ACTIONS.include?(action)
|
|
482
|
+
authorization
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
def split_authorization(authorization)
|
|
486
|
+
authorization&.split('|')
|
|
487
|
+
end
|
|
448
488
|
end
|
|
449
489
|
end
|
|
450
490
|
end
|
|
@@ -33,9 +33,9 @@ module ActiveMerchant #:nodoc:
|
|
|
33
33
|
'10110' => STANDARD_ERROR_CODE[:incorrect_address],
|
|
34
34
|
'10111' => STANDARD_ERROR_CODE[:incorrect_address],
|
|
35
35
|
'10127' => STANDARD_ERROR_CODE[:card_declined],
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
36
|
+
'00043' => STANDARD_ERROR_CODE[:call_issuer],
|
|
37
|
+
'10205' => STANDARD_ERROR_CODE[:card_declined],
|
|
38
|
+
'10204' => STANDARD_ERROR_CODE[:pickup_card]
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
def initialize(options = {})
|
|
@@ -197,14 +197,19 @@ module ActiveMerchant #:nodoc:
|
|
|
197
197
|
end
|
|
198
198
|
|
|
199
199
|
def add_invoice(post, options)
|
|
200
|
-
post[:invoice] = options[:
|
|
200
|
+
post[:invoice] = options[:invoice]
|
|
201
|
+
post[:orderid] = options[:order_id]
|
|
201
202
|
post[:description] = options[:description]
|
|
202
203
|
end
|
|
203
204
|
|
|
204
205
|
def add_payment(post, payment, options={})
|
|
205
206
|
if payment.respond_to?(:routing_number)
|
|
206
207
|
post[:checkformat] = options[:check_format] if options[:check_format]
|
|
207
|
-
|
|
208
|
+
if payment.account_type
|
|
209
|
+
account_type = payment.account_type.to_s.capitalize
|
|
210
|
+
raise ArgumentError, 'account_type must be checking or savings' unless %w(Checking Savings).include?(account_type)
|
|
211
|
+
post[:accounttype] = account_type
|
|
212
|
+
end
|
|
208
213
|
post[:account] = payment.account_number
|
|
209
214
|
post[:routing] = payment.routing_number
|
|
210
215
|
post[:name] = payment.name unless payment.name.blank?
|
|
@@ -258,7 +263,10 @@ module ActiveMerchant #:nodoc:
|
|
|
258
263
|
# see: https://wiki.usaepay.com/developer/transactionapi#merchant_defined_custom_fields
|
|
259
264
|
def add_custom_fields(post, options)
|
|
260
265
|
return unless options[:custom_fields].is_a?(Hash)
|
|
266
|
+
|
|
261
267
|
options[:custom_fields].each do |index, custom|
|
|
268
|
+
raise ArgumentError.new('Cannot specify custom field with index 0') if index.to_s.to_i.zero?
|
|
269
|
+
|
|
262
270
|
post["custom#{index}"] = custom
|
|
263
271
|
end
|
|
264
272
|
end
|
|
@@ -267,7 +275,7 @@ module ActiveMerchant #:nodoc:
|
|
|
267
275
|
def add_line_items(post, options)
|
|
268
276
|
return unless options[:line_items].is_a?(Array)
|
|
269
277
|
options[:line_items].each_with_index do |line_item, index|
|
|
270
|
-
%w(product_ref_num sku name description taxable tax_rate tax_amount commodity_code discount_rate discount_amount).each do |key|
|
|
278
|
+
%w(product_ref_num sku qty name description taxable tax_rate tax_amount commodity_code discount_rate discount_amount).each do |key|
|
|
271
279
|
post["line#{index}#{key.delete('_')}"] = line_item[key.to_sym] if line_item.has_key?(key.to_sym)
|
|
272
280
|
end
|
|
273
281
|
|
|
@@ -310,12 +318,15 @@ module ActiveMerchant #:nodoc:
|
|
|
310
318
|
def commit(action, parameters)
|
|
311
319
|
url = (test? ? self.test_url : self.live_url)
|
|
312
320
|
response = parse(ssl_post(url, post_data(action, parameters)))
|
|
313
|
-
|
|
321
|
+
approved = response[:status] == 'Approved'
|
|
322
|
+
error_code = nil
|
|
323
|
+
error_code = (STANDARD_ERROR_CODE_MAPPING[response[:error_code]] || STANDARD_ERROR_CODE[:processing_error]) unless approved
|
|
324
|
+
Response.new(approved, message_from(response), response,
|
|
314
325
|
:test => test?,
|
|
315
326
|
:authorization => response[:ref_num],
|
|
316
327
|
:cvv_result => response[:cvv2_result_code],
|
|
317
328
|
:avs_result => { :code => response[:avs_result_code] },
|
|
318
|
-
:error_code =>
|
|
329
|
+
:error_code => error_code
|
|
319
330
|
)
|
|
320
331
|
end
|
|
321
332
|
|
|
@@ -57,7 +57,10 @@ module ActiveMerchant #:nodoc:
|
|
|
57
57
|
response = commit('cancelDeposit', params, options)
|
|
58
58
|
return response if response.success? || split_authorization(authorization).length == 1 || !options[:force_full_refund_if_unsettled]
|
|
59
59
|
|
|
60
|
-
# Attempt RefundSingleTransaction if unsettled
|
|
60
|
+
# Attempt RefundSingleTransaction if unsettled (and stash the original
|
|
61
|
+
# response message so it will be included it in the follow-up response
|
|
62
|
+
# message)
|
|
63
|
+
options[:error_message] = response.message
|
|
61
64
|
prepare_refund_data(params, authorization, options)
|
|
62
65
|
commit('refund', params, options)
|
|
63
66
|
end
|
|
@@ -197,15 +200,24 @@ module ActiveMerchant #:nodoc:
|
|
|
197
200
|
end
|
|
198
201
|
|
|
199
202
|
def message_from(response, options, action)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
message_from_messages(
|
|
204
|
+
response['errorMessage'],
|
|
205
|
+
action_code_description(response),
|
|
206
|
+
options[:error_message]
|
|
207
|
+
)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def message_from_messages(*args)
|
|
211
|
+
args.reject { |m| error_message_empty?(m) }.join(' | ')
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def action_code_description(response)
|
|
215
|
+
return nil unless response['data']
|
|
216
|
+
response['data']['DSC_COD_ACCION']
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def error_message_empty?(error_message)
|
|
220
|
+
empty?(error_message) || error_message == '[ ]'
|
|
209
221
|
end
|
|
210
222
|
|
|
211
223
|
def response_error(raw_response, options, action)
|