activemerchant 1.121.0 → 1.125.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 +217 -0
- data/README.md +1 -1
- data/lib/active_merchant/billing/check.rb +13 -19
- data/lib/active_merchant/billing/credit_card.rb +13 -0
- data/lib/active_merchant/billing/credit_card_formatting.rb +1 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +24 -12
- data/lib/active_merchant/billing/gateway.rb +1 -1
- data/lib/active_merchant/billing/gateways/adyen.rb +75 -27
- data/lib/active_merchant/billing/gateways/authorize_net.rb +10 -8
- data/lib/active_merchant/billing/gateways/blue_pay.rb +29 -0
- data/lib/active_merchant/billing/gateways/blue_snap.rb +2 -2
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +6 -3
- data/lib/active_merchant/billing/gateways/card_stream.rb +17 -13
- data/lib/active_merchant/billing/gateways/cashnet.rb +15 -5
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +33 -4
- data/lib/active_merchant/billing/gateways/credorax.rb +2 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +41 -6
- data/lib/active_merchant/billing/gateways/d_local.rb +12 -6
- data/lib/active_merchant/billing/gateways/decidir.rb +7 -1
- data/lib/active_merchant/billing/gateways/decidir_plus.rb +173 -0
- data/lib/active_merchant/billing/gateways/ebanx.rb +16 -1
- data/lib/active_merchant/billing/gateways/elavon.rb +65 -30
- data/lib/active_merchant/billing/gateways/element.rb +22 -2
- data/lib/active_merchant/billing/gateways/global_collect.rb +130 -26
- data/lib/active_merchant/billing/gateways/ipg.rb +416 -0
- data/lib/active_merchant/billing/gateways/kushki.rb +30 -0
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +6 -3
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -0
- data/lib/active_merchant/billing/gateways/mit.rb +260 -0
- data/lib/active_merchant/billing/gateways/moka.rb +290 -0
- data/lib/active_merchant/billing/gateways/monei.rb +228 -144
- data/lib/active_merchant/billing/gateways/mundipagg.rb +22 -11
- data/lib/active_merchant/billing/gateways/nmi.rb +29 -10
- data/lib/active_merchant/billing/gateways/orbital.rb +46 -8
- data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
- data/lib/active_merchant/billing/gateways/pay_conex.rb +3 -1
- data/lib/active_merchant/billing/gateways/pay_trace.rb +404 -0
- data/lib/active_merchant/billing/gateways/payeezy.rb +4 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +21 -4
- data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
- data/lib/active_merchant/billing/gateways/paymentez.rb +14 -2
- data/lib/active_merchant/billing/gateways/paysafe.rb +412 -0
- data/lib/active_merchant/billing/gateways/payu_latam.rb +9 -4
- data/lib/active_merchant/billing/gateways/payway_dot_com.rb +3 -3
- data/lib/active_merchant/billing/gateways/pin.rb +31 -4
- data/lib/active_merchant/billing/gateways/priority.rb +347 -0
- data/lib/active_merchant/billing/gateways/realex.rb +18 -0
- data/lib/active_merchant/billing/gateways/redsys.rb +35 -32
- data/lib/active_merchant/billing/gateways/safe_charge.rb +8 -2
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +13 -4
- data/lib/active_merchant/billing/gateways/stripe.rb +27 -7
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +115 -39
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -1
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +2 -1
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +21 -7
- data/lib/active_merchant/billing/gateways/vpos.rb +49 -6
- data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +226 -62
- data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
- data/lib/active_merchant/billing/response.rb +4 -0
- data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
- data/lib/active_merchant/billing.rb +1 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +13 -3
@@ -0,0 +1,193 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class WompiGateway < Gateway
|
4
|
+
self.test_url = 'https://sync.sandbox.wompi.co/v1'
|
5
|
+
self.live_url = 'https://sync.production.wompi.co/v1'
|
6
|
+
|
7
|
+
self.supported_countries = ['CO']
|
8
|
+
self.default_currency = 'COP'
|
9
|
+
self.supported_cardtypes = %i[visa master american_express]
|
10
|
+
|
11
|
+
self.homepage_url = 'https://wompi.co/'
|
12
|
+
self.display_name = 'Wompi'
|
13
|
+
|
14
|
+
self.money_format = :cents
|
15
|
+
|
16
|
+
def initialize(options = {})
|
17
|
+
## Sandbox keys have prefix pub_test_ and prv_test_
|
18
|
+
## Production keys have prefix pub_prod_ and prv_prod_
|
19
|
+
begin
|
20
|
+
requires!(options, :prod_private_key, :prod_public_key)
|
21
|
+
rescue ArgumentError
|
22
|
+
begin
|
23
|
+
requires!(options, :test_private_key, :test_public_key)
|
24
|
+
rescue ArgumentError
|
25
|
+
raise ArgumentError, 'Gateway requires both test_private_key and test_public_key, or both prod_private_key and prod_public_key'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def purchase(money, payment, options = {})
|
32
|
+
post = {
|
33
|
+
reference: options[:reference] || generate_reference,
|
34
|
+
public_key: public_key
|
35
|
+
}
|
36
|
+
add_invoice(post, money, options)
|
37
|
+
add_card(post, payment, options)
|
38
|
+
|
39
|
+
commit('sale', post, '/transactions_sync')
|
40
|
+
end
|
41
|
+
|
42
|
+
def authorize(money, payment, options = {})
|
43
|
+
post = {
|
44
|
+
public_key: public_key,
|
45
|
+
type: 'CARD',
|
46
|
+
financial_operation: 'PREAUTHORIZATION'
|
47
|
+
}
|
48
|
+
add_auth_params(post, money, payment, options)
|
49
|
+
|
50
|
+
commit('authorize', post, '/payment_sources_sync')
|
51
|
+
end
|
52
|
+
|
53
|
+
def capture(money, authorization, options = {})
|
54
|
+
post = {
|
55
|
+
reference: options[:reference] || generate_reference,
|
56
|
+
public_key: public_key,
|
57
|
+
payment_source_id: authorization.to_i
|
58
|
+
}
|
59
|
+
add_invoice(post, money, options)
|
60
|
+
commit('capture', post, '/transactions_sync')
|
61
|
+
end
|
62
|
+
|
63
|
+
def refund(money, authorization, options = {})
|
64
|
+
post = { amount_in_cents: amount(money).to_i, transaction_id: authorization.to_s }
|
65
|
+
commit('refund', post, '/refunds_sync')
|
66
|
+
end
|
67
|
+
|
68
|
+
def void(authorization, options = {})
|
69
|
+
commit('void', {}, "/transactions/#{authorization}/void_sync")
|
70
|
+
end
|
71
|
+
|
72
|
+
def supports_scrubbing?
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
def scrub(transcript)
|
77
|
+
transcript.gsub(/(Bearer )\w+/, '\1[REDACTED]').
|
78
|
+
gsub(/(\\\"number\\\":\\\")\d+/, '\1[REDACTED]').
|
79
|
+
gsub(/(\\\"cvc\\\":\\\")\d+/, '\1[REDACTED]').
|
80
|
+
gsub(/(\\\"phone_number\\\":\\\")\+?\d+/, '\1[REDACTED]').
|
81
|
+
gsub(/(\\\"email\\\":\\\")\S+\\\",/, '\1[REDACTED]\",').
|
82
|
+
gsub(/(\\\"legal_id\\\":\\\")\d+/, '\1[REDACTED]')
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def headers
|
88
|
+
{
|
89
|
+
'Authorization' => "Bearer #{private_key}",
|
90
|
+
'Content-Type' => 'application/json'
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
def generate_reference
|
95
|
+
SecureRandom.alphanumeric(12)
|
96
|
+
end
|
97
|
+
|
98
|
+
def private_key
|
99
|
+
test? ? options[:test_private_key] : options[:prod_private_key]
|
100
|
+
end
|
101
|
+
|
102
|
+
def public_key
|
103
|
+
test? ? options[:test_public_key] : options[:prod_public_key]
|
104
|
+
end
|
105
|
+
|
106
|
+
def add_invoice(post, money, options)
|
107
|
+
post[:amount_in_cents] = amount(money).to_i
|
108
|
+
post[:currency] = (options[:currency] || currency(money))
|
109
|
+
end
|
110
|
+
|
111
|
+
def add_card(post, card, options)
|
112
|
+
payment_method = {
|
113
|
+
type: 'CARD'
|
114
|
+
}
|
115
|
+
add_basic_card_info(payment_method, card, options)
|
116
|
+
post[:payment_method] = payment_method
|
117
|
+
end
|
118
|
+
|
119
|
+
def add_auth_params(post, money, card, options)
|
120
|
+
data = {
|
121
|
+
amount_in_cents: amount(money).to_i,
|
122
|
+
currency: (options[:currency] || currency(money))
|
123
|
+
}
|
124
|
+
add_basic_card_info(data, card, options)
|
125
|
+
post[:data] = data
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_basic_card_info(post, card, options)
|
129
|
+
installments = options[:installments] ? options[:installments].to_i : 1
|
130
|
+
cvc = card.verification_value || nil
|
131
|
+
|
132
|
+
post[:number] = card.number
|
133
|
+
post[:exp_month] = card.month.to_s.rjust(2, '0')
|
134
|
+
post[:exp_year] = card.year.to_s[2..3]
|
135
|
+
post[:installments] = installments
|
136
|
+
post[:card_holder] = card.name
|
137
|
+
post[:cvc] = cvc if cvc && !cvc.empty?
|
138
|
+
end
|
139
|
+
|
140
|
+
def parse(body)
|
141
|
+
JSON.parse(body)
|
142
|
+
end
|
143
|
+
|
144
|
+
def commit(action, parameters, endpoint)
|
145
|
+
url = (test? ? test_url : live_url) + endpoint
|
146
|
+
response = parse(ssl_post(url, post_data(action, parameters), headers))
|
147
|
+
Response.new(
|
148
|
+
success_from(response),
|
149
|
+
message_from(response),
|
150
|
+
response,
|
151
|
+
authorization: authorization_from(response),
|
152
|
+
avs_result: nil,
|
153
|
+
cvv_result: nil,
|
154
|
+
test: test?,
|
155
|
+
error_code: error_code_from(response)
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
def handle_response(response)
|
160
|
+
case response.code.to_i
|
161
|
+
when 200...300, 401, 404, 422
|
162
|
+
response.body
|
163
|
+
else
|
164
|
+
raise ResponseError.new(response)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def success_from(response)
|
169
|
+
success_statuses.include? response.dig('data', 'status')
|
170
|
+
end
|
171
|
+
|
172
|
+
def success_statuses
|
173
|
+
%w(APPROVED AVAILABLE)
|
174
|
+
end
|
175
|
+
|
176
|
+
def message_from(response)
|
177
|
+
response.dig('data', 'status_message') || response.dig('error', 'reason') || response.dig('error', 'messages').to_json
|
178
|
+
end
|
179
|
+
|
180
|
+
def authorization_from(response)
|
181
|
+
response.dig('data', 'transaction_id') || response.dig('data', 'id') || response.dig('data', 'transaction', 'id')
|
182
|
+
end
|
183
|
+
|
184
|
+
def post_data(action, parameters = {})
|
185
|
+
parameters.to_json
|
186
|
+
end
|
187
|
+
|
188
|
+
def error_code_from(response)
|
189
|
+
response.dig('error', 'type') unless success_from(response)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -8,13 +8,26 @@ module ActiveMerchant #:nodoc:
|
|
8
8
|
|
9
9
|
self.default_currency = 'GBP'
|
10
10
|
self.money_format = :cents
|
11
|
-
self.supported_countries = %w(
|
11
|
+
self.supported_countries = %w(AD AE AG AI AL AM AO AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BM BN BO BR BS BT BW
|
12
|
+
BY BZ CA CC CF CH CK CL CM CN CO CR CV CX CY CZ DE DJ DK DO DZ EC EE EG EH ES ET FI FJ FK
|
13
|
+
FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GT GU GW GY HK HM HN HR HT HU ID IE IL
|
14
|
+
IM IN IO IS IT JE JM JO JP KE KG KH KI KM KN KR KW KY KZ LA LC LI LK LS LT LU LV MA MC MD
|
15
|
+
ME MG MH MK ML 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
|
16
|
+
OM PA PE PF PH PK PL PN PR PT PW PY QA RE RO RS RU RW SA SB SC SE SG SI SK SL SM SN ST SV
|
17
|
+
SZ TC TD TF TG TH TJ TK TM TO TR TT TV TW TZ UA UG US UY UZ VA VC VE VI VN VU WF WS YE YT
|
18
|
+
ZA ZM)
|
12
19
|
self.supported_cardtypes = %i[visa master american_express discover jcb maestro elo naranja cabal unionpay]
|
13
|
-
self.currencies_without_fractions = %w(HUF IDR
|
14
|
-
self.currencies_with_three_decimal_places = %w(BHD KWD OMR
|
20
|
+
self.currencies_without_fractions = %w(HUF IDR JPY KRW BEF XOF XAF XPF GRD GNF ITL LUF MGA MGF PYG PTE RWF ESP TRL VND KMF)
|
21
|
+
self.currencies_with_three_decimal_places = %w(BHD KWD OMR TND LYD JOD IQD)
|
15
22
|
self.homepage_url = 'http://www.worldpay.com/'
|
16
23
|
self.display_name = 'Worldpay Global'
|
17
24
|
|
25
|
+
NETWORK_TOKEN_TYPE = {
|
26
|
+
apple_pay: 'APPLEPAY',
|
27
|
+
google_pay: 'GOOGLEPAY',
|
28
|
+
network_token: 'NETWORKTOKEN'
|
29
|
+
}
|
30
|
+
|
18
31
|
CARD_CODES = {
|
19
32
|
'visa' => 'VISA-SSL',
|
20
33
|
'master' => 'ECMC-SSL',
|
@@ -64,7 +77,7 @@ module ActiveMerchant #:nodoc:
|
|
64
77
|
|
65
78
|
def authorize(money, payment_method, options = {})
|
66
79
|
requires!(options, :order_id)
|
67
|
-
payment_details =
|
80
|
+
payment_details = payment_details(payment_method)
|
68
81
|
authorize_request(money, payment_method, payment_details.merge(options))
|
69
82
|
end
|
70
83
|
|
@@ -110,13 +123,18 @@ module ActiveMerchant #:nodoc:
|
|
110
123
|
# and other transactions should be performed on a normal eCom-flagged
|
111
124
|
# merchant ID.
|
112
125
|
def credit(money, payment_method, options = {})
|
113
|
-
payment_details =
|
114
|
-
|
126
|
+
payment_details = payment_details(payment_method)
|
127
|
+
if options[:fast_fund_credit]
|
128
|
+
fast_fund_credit_request(money, payment_method, payment_details.merge(credit: true, **options))
|
129
|
+
else
|
130
|
+
credit_request(money, payment_method, payment_details.merge(credit: true, **options))
|
131
|
+
end
|
115
132
|
end
|
116
133
|
|
117
134
|
def verify(payment_method, options = {})
|
135
|
+
amount = (eligible_for_0_auth?(payment_method, options) ? 0 : 100)
|
118
136
|
MultiResponse.run(:use_first_response) do |r|
|
119
|
-
r.process { authorize(
|
137
|
+
r.process { authorize(amount, payment_method, options) }
|
120
138
|
r.process(:ignore_result) { void(r.authorization, options.merge(authorization_validated: true)) }
|
121
139
|
end
|
122
140
|
end
|
@@ -130,17 +148,23 @@ module ActiveMerchant #:nodoc:
|
|
130
148
|
true
|
131
149
|
end
|
132
150
|
|
151
|
+
def supports_network_tokenization?
|
152
|
+
true
|
153
|
+
end
|
154
|
+
|
133
155
|
def scrub(transcript)
|
134
156
|
transcript.
|
135
157
|
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
|
136
158
|
gsub(%r((<cardNumber>)\d+(</cardNumber>)), '\1[FILTERED]\2').
|
137
|
-
gsub(%r((<cvc>)[^<]+(</cvc>)), '\1[FILTERED]\2')
|
159
|
+
gsub(%r((<cvc>)[^<]+(</cvc>)), '\1[FILTERED]\2').
|
160
|
+
gsub(%r((<tokenNumber>)\d+(</tokenNumber>)), '\1[FILTERED]\2').
|
161
|
+
gsub(%r((<cryptogram>)[^<]+(</cryptogram>)), '\1[FILTERED]\2')
|
138
162
|
end
|
139
163
|
|
140
164
|
private
|
141
165
|
|
142
166
|
def authorize_request(money, payment_method, options)
|
143
|
-
commit('authorize', build_authorization_request(money, payment_method, options), 'AUTHORISED', options)
|
167
|
+
commit('authorize', build_authorization_request(money, payment_method, options), 'AUTHORISED', 'CAPTURED', options)
|
144
168
|
end
|
145
169
|
|
146
170
|
def capture_request(money, authorization, options)
|
@@ -163,6 +187,10 @@ module ActiveMerchant #:nodoc:
|
|
163
187
|
commit('credit', build_authorization_request(money, payment_method, options), :ok, 'SENT_FOR_REFUND', options)
|
164
188
|
end
|
165
189
|
|
190
|
+
def fast_fund_credit_request(money, payment_method, options)
|
191
|
+
commit('fast_credit', build_fast_fund_credit_request(money, payment_method, options), :ok, 'PUSH_APPROVED', options)
|
192
|
+
end
|
193
|
+
|
166
194
|
def store_request(credit_card, options)
|
167
195
|
commit('store', build_store_request(credit_card, options), options)
|
168
196
|
end
|
@@ -201,15 +229,12 @@ module ActiveMerchant #:nodoc:
|
|
201
229
|
xml.order order_tag_attributes(options) do
|
202
230
|
xml.description(options[:description].blank? ? 'Purchase' : options[:description])
|
203
231
|
add_amount(xml, money, options)
|
204
|
-
|
205
|
-
xml.orderContent do
|
206
|
-
xml.cdata! options[:order_content]
|
207
|
-
end
|
208
|
-
end
|
232
|
+
add_order_content(xml, options)
|
209
233
|
add_payment_method(xml, money, payment_method, options)
|
210
234
|
add_shopper(xml, options)
|
211
235
|
add_statement_narrative(xml, options)
|
212
236
|
add_risk_data(xml, options[:risk_data]) if options[:risk_data]
|
237
|
+
add_sub_merchant_data(xml, options[:sub_merchant_data]) if options[:sub_merchant_data]
|
213
238
|
add_hcg_additional_data(xml, options) if options[:hcg_additional_data]
|
214
239
|
add_instalments_data(xml, options) if options[:instalments]
|
215
240
|
add_moto_flag(xml, options) if options.dig(:metadata, :manual_entry)
|
@@ -221,7 +246,19 @@ module ActiveMerchant #:nodoc:
|
|
221
246
|
end
|
222
247
|
|
223
248
|
def order_tag_attributes(options)
|
224
|
-
{ 'orderCode' => options[:order_id], 'installationId' => options[:inst_id] || @options[:inst_id] }.reject { |_, v| !v.present? }
|
249
|
+
{ 'orderCode' => clean_order_id(options[:order_id]), 'installationId' => options[:inst_id] || @options[:inst_id] }.reject { |_, v| !v.present? }
|
250
|
+
end
|
251
|
+
|
252
|
+
def clean_order_id(order_id)
|
253
|
+
order_id.to_s.gsub(/(\s|\||<|>|'|")/, '')[0..64]
|
254
|
+
end
|
255
|
+
|
256
|
+
def add_order_content(xml, options)
|
257
|
+
return unless options[:order_content]
|
258
|
+
|
259
|
+
xml.orderContent do
|
260
|
+
xml.cdata! options[:order_content]
|
261
|
+
end
|
225
262
|
end
|
226
263
|
|
227
264
|
def build_capture_request(money, authorization, options)
|
@@ -235,7 +272,11 @@ module ActiveMerchant #:nodoc:
|
|
235
272
|
end
|
236
273
|
|
237
274
|
def build_void_request(authorization, options)
|
238
|
-
|
275
|
+
if options[:cancel_or_refund]
|
276
|
+
build_order_modify_request(authorization, &:cancelOrRefund)
|
277
|
+
else
|
278
|
+
build_order_modify_request(authorization, &:cancel)
|
279
|
+
end
|
239
280
|
end
|
240
281
|
|
241
282
|
def build_refund_request(money, authorization, options)
|
@@ -262,11 +303,69 @@ module ActiveMerchant #:nodoc:
|
|
262
303
|
add_card(xml, credit_card, options)
|
263
304
|
end
|
264
305
|
end
|
306
|
+
add_transaction_identifier(xml, options) if network_transaction_id(options)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def network_transaction_id(options)
|
313
|
+
options[:stored_credential_transaction_id] || options.dig(:stored_credential, :network_transaction_id)
|
314
|
+
end
|
315
|
+
|
316
|
+
def add_transaction_identifier(xml, options)
|
317
|
+
xml.storedCredentials 'usage' => 'FIRST' do
|
318
|
+
xml.schemeTransactionIdentifier network_transaction_id(options)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def build_fast_fund_credit_request(money, payment_method, options)
|
323
|
+
build_request do |xml|
|
324
|
+
xml.submit do
|
325
|
+
xml.order order_tag_attributes(options) do
|
326
|
+
xml.description(options[:description].blank? ? 'Fast Fund Credit' : options[:description])
|
327
|
+
add_amount(xml, money, options)
|
328
|
+
add_order_content(xml, options)
|
329
|
+
add_payment_details_for_ff_credit(xml, payment_method, options)
|
330
|
+
add_shopper_id(xml, options)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def add_payment_details_for_ff_credit(xml, payment_method, options)
|
337
|
+
xml.paymentDetails do
|
338
|
+
xml.tag! 'FF_DISBURSE-SSL' do
|
339
|
+
if payment_method.is_a?(CreditCard)
|
340
|
+
add_card_for_ff_credit(xml, payment_method, options)
|
341
|
+
else
|
342
|
+
add_token_for_ff_credit(xml, payment_method, options)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def add_card_for_ff_credit(xml, payment_method, options)
|
349
|
+
xml.recipient do
|
350
|
+
xml.paymentInstrument do
|
351
|
+
xml.cardDetails do
|
352
|
+
add_card(xml, payment_method, options)
|
265
353
|
end
|
266
354
|
end
|
267
355
|
end
|
268
356
|
end
|
269
357
|
|
358
|
+
def add_token_for_ff_credit(xml, payment_method, options)
|
359
|
+
return unless payment_method.is_a?(String)
|
360
|
+
|
361
|
+
token_details = token_details_from_authorization(payment_method)
|
362
|
+
|
363
|
+
xml.tag! 'recipient', 'tokenScope' => token_details[:token_scope] do
|
364
|
+
xml.paymentTokenID token_details[:token_id]
|
365
|
+
add_authenticated_shopper_id(xml, token_details)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
270
369
|
def add_additional_3ds_data(xml, options)
|
271
370
|
additional_data = { 'dfReferenceId' => options[:session_id] }
|
272
371
|
additional_data['challengeWindowSize'] = options[:browser_size] if options[:browser_size]
|
@@ -305,6 +404,20 @@ module ActiveMerchant #:nodoc:
|
|
305
404
|
end
|
306
405
|
end
|
307
406
|
|
407
|
+
def add_sub_merchant_data(xml, options)
|
408
|
+
xml.subMerchantData do
|
409
|
+
xml.pfId options[:pf_id] if options[:pf_id]
|
410
|
+
xml.subName options[:sub_name] if options[:sub_name]
|
411
|
+
xml.subId options[:sub_id] if options[:sub_id]
|
412
|
+
xml.subStreet options[:sub_street] if options[:sub_street]
|
413
|
+
xml.subCity options[:sub_city] if options[:sub_city]
|
414
|
+
xml.subState options[:sub_state] if options[:sub_state]
|
415
|
+
xml.subCountryCode options[:sub_country_code] if options[:sub_country_code]
|
416
|
+
xml.subPostalCode options[:sub_postal_code] if options[:sub_postal_code]
|
417
|
+
xml.subTaxId options[:sub_tax_id] if options[:sub_tax_id]
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
308
421
|
def add_shopper_account_risk_data(xml, shopper_account_risk_data)
|
309
422
|
return unless shopper_account_risk_data
|
310
423
|
|
@@ -379,46 +492,89 @@ module ActiveMerchant #:nodoc:
|
|
379
492
|
end
|
380
493
|
|
381
494
|
def add_payment_method(xml, amount, payment_method, options)
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
495
|
+
case options[:payment_type]
|
496
|
+
when :pay_as_order
|
497
|
+
add_amount_for_pay_as_order(xml, amount, payment_method, options)
|
498
|
+
when :network_token
|
499
|
+
add_network_tokenization_card(xml, payment_method)
|
500
|
+
else
|
501
|
+
add_card_or_token(xml, payment_method, options)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
def add_amount_for_pay_as_order(xml, amount, payment_method, options)
|
506
|
+
if options[:merchant_code]
|
507
|
+
xml.payAsOrder 'orderCode' => payment_method, 'merchantCode' => options[:merchant_code] do
|
508
|
+
add_amount(xml, amount, options)
|
391
509
|
end
|
392
510
|
else
|
393
|
-
xml.
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
end
|
402
|
-
end
|
403
|
-
add_stored_credential_options(xml, options)
|
404
|
-
if options[:ip] && options[:session_id]
|
405
|
-
xml.session 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
|
406
|
-
else
|
407
|
-
xml.session 'shopperIPAddress' => options[:ip] if options[:ip]
|
408
|
-
xml.session 'id' => options[:session_id] if options[:session_id]
|
409
|
-
end
|
511
|
+
xml.payAsOrder 'orderCode' => payment_method do
|
512
|
+
add_amount(xml, amount, options)
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
def add_network_tokenization_card(xml, payment_method)
|
518
|
+
token_type = NETWORK_TOKEN_TYPE.fetch(payment_method.source, 'NETWORKTOKEN')
|
410
519
|
|
411
|
-
|
412
|
-
|
520
|
+
xml.paymentDetails do
|
521
|
+
xml.tag! 'EMVCO_TOKEN-SSL', 'type' => token_type do
|
522
|
+
xml.tokenNumber payment_method.number
|
523
|
+
xml.expiryDate do
|
524
|
+
xml.date(
|
525
|
+
'month' => format(payment_method.month, :two_digits),
|
526
|
+
'year' => format(payment_method.year, :four_digits_year)
|
527
|
+
)
|
413
528
|
end
|
529
|
+
name = card_holder_name(payment_method, options)
|
530
|
+
eci = format(payment_method.eci, :two_digits)
|
531
|
+
xml.cardHolderName name if name.present?
|
532
|
+
xml.cryptogram payment_method.payment_cryptogram
|
533
|
+
xml.eciIndicator eci.empty? ? '07' : eci
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
def add_card_or_token(xml, payment_method, options)
|
539
|
+
xml.paymentDetails credit_fund_transfer_attribute(options) do
|
540
|
+
if options[:payment_type] == :token
|
541
|
+
add_token_details(xml, options)
|
542
|
+
else
|
543
|
+
add_card_details(xml, payment_method, options)
|
414
544
|
end
|
545
|
+
add_stored_credential_options(xml, options)
|
546
|
+
add_shopper_id(xml, options)
|
547
|
+
add_three_d_secure(xml, options)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
def add_token_details(xml, options)
|
552
|
+
xml.tag! 'TOKEN-SSL', 'tokenScope' => options[:token_scope] do
|
553
|
+
xml.paymentTokenID options[:token_id]
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
def add_card_details(xml, payment_method, options)
|
558
|
+
xml.tag! card_code_for(payment_method) do
|
559
|
+
add_card(xml, payment_method, options)
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
def add_shopper_id(xml, options)
|
564
|
+
if options[:ip] && options[:session_id]
|
565
|
+
xml.session 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
|
566
|
+
else
|
567
|
+
xml.session 'shopperIPAddress' => options[:ip] if options[:ip]
|
568
|
+
xml.session 'id' => options[:session_id] if options[:session_id]
|
415
569
|
end
|
416
570
|
end
|
417
571
|
|
418
|
-
def add_three_d_secure(
|
572
|
+
def add_three_d_secure(xml, options)
|
573
|
+
return unless three_d_secure = options[:three_d_secure]
|
574
|
+
|
419
575
|
xml.info3DSecure do
|
420
576
|
xml.threeDSVersion three_d_secure[:version]
|
421
|
-
if
|
577
|
+
if three_d_secure[:version] && three_d_secure[:ds_transaction_id]
|
422
578
|
xml.dsTransactionId three_d_secure[:ds_transaction_id]
|
423
579
|
else
|
424
580
|
xml.xid three_d_secure[:xid]
|
@@ -433,12 +589,10 @@ module ActiveMerchant #:nodoc:
|
|
433
589
|
xml.expiryDate do
|
434
590
|
xml.date(
|
435
591
|
'month' => format(payment_method.month, :two_digits),
|
436
|
-
'year' => format(payment_method.year, :
|
592
|
+
'year' => format(payment_method.year, :four_digits_year)
|
437
593
|
)
|
438
594
|
end
|
439
|
-
|
440
|
-
card_holder_name = test? && options[:execute_threed] && !options[:three_ds_version]&.start_with?('2') ? '3D' : payment_method.name
|
441
|
-
xml.cardHolderName card_holder_name
|
595
|
+
xml.cardHolderName card_holder_name(payment_method, options)
|
442
596
|
xml.cvc payment_method.verification_value
|
443
597
|
|
444
598
|
add_address(xml, (options[:billing_address] || options[:address]), options)
|
@@ -600,6 +754,7 @@ module ActiveMerchant #:nodoc:
|
|
600
754
|
def commit(action, request, *success_criteria, options)
|
601
755
|
xml = ssl_post(url, request, headers(options))
|
602
756
|
raw = parse(action, xml)
|
757
|
+
|
603
758
|
if options[:execute_threed]
|
604
759
|
raw[:cookie] = @cookie if defined?(@cookie)
|
605
760
|
raw[:session_id] = options[:session_id]
|
@@ -728,21 +883,22 @@ module ActiveMerchant #:nodoc:
|
|
728
883
|
token_details
|
729
884
|
end
|
730
885
|
|
731
|
-
def
|
732
|
-
|
733
|
-
|
734
|
-
|
886
|
+
def payment_details(payment_method)
|
887
|
+
case payment_method
|
888
|
+
when String
|
889
|
+
token_type_and_details(payment_method)
|
890
|
+
when NetworkTokenizationCreditCard
|
891
|
+
{ payment_type: :network_token }
|
735
892
|
else
|
736
|
-
|
737
|
-
payment_details.merge!(token_details)
|
738
|
-
if token_details.has_key?(:token_id)
|
739
|
-
payment_details[:payment_type] = :token
|
740
|
-
else
|
741
|
-
payment_details[:payment_type] = :pay_as_order
|
742
|
-
end
|
893
|
+
{ payment_type: :credit }
|
743
894
|
end
|
895
|
+
end
|
744
896
|
|
745
|
-
|
897
|
+
def token_type_and_details(token)
|
898
|
+
token_details = token_details_from_authorization(token)
|
899
|
+
token_details[:payment_type] = token_details.has_key?(:token_id) ? :token : :pay_as_order
|
900
|
+
|
901
|
+
token_details
|
746
902
|
end
|
747
903
|
|
748
904
|
def credit_fund_transfer_attribute(options)
|
@@ -766,6 +922,14 @@ module ActiveMerchant #:nodoc:
|
|
766
922
|
def card_code_for(payment_method)
|
767
923
|
CARD_CODES[card_brand(payment_method)] || CARD_CODES['unknown']
|
768
924
|
end
|
925
|
+
|
926
|
+
def eligible_for_0_auth?(payment_method, options = {})
|
927
|
+
payment_method.is_a?(CreditCard) && %w(visa master).include?(payment_method.brand) && options[:zero_dollar_auth]
|
928
|
+
end
|
929
|
+
|
930
|
+
def card_holder_name(payment_method, options)
|
931
|
+
test? && options[:execute_threed] && !options[:three_ds_version]&.start_with?('2') ? '3D' : payment_method.name
|
932
|
+
end
|
769
933
|
end
|
770
934
|
end
|
771
935
|
end
|
@@ -14,7 +14,7 @@ module ActiveMerchant #:nodoc:
|
|
14
14
|
self.require_verification_value = false
|
15
15
|
self.require_name = false
|
16
16
|
|
17
|
-
attr_accessor :payment_cryptogram, :eci, :transaction_id
|
17
|
+
attr_accessor :payment_cryptogram, :eci, :transaction_id, :metadata
|
18
18
|
attr_writer :source
|
19
19
|
|
20
20
|
SOURCES = %i(apple_pay android_pay google_pay network_token)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActiveMerchant
|
2
|
+
module Billing
|
3
|
+
module ThreeDSecureEciMapper
|
4
|
+
NON_THREE_D_SECURE_TRANSACTION = :non_three_d_secure_transaction
|
5
|
+
ATTEMPTED_AUTHENTICATION_TRANSACTION = :attempted_authentication_transaction
|
6
|
+
FULLY_AUTHENTICATED_TRANSACTION = :fully_authenticated_transaction
|
7
|
+
|
8
|
+
ECI_00_01_02_MAP = { '00' => NON_THREE_D_SECURE_TRANSACTION, '01' => ATTEMPTED_AUTHENTICATION_TRANSACTION, '02' => FULLY_AUTHENTICATED_TRANSACTION }.freeze
|
9
|
+
ECI_05_06_07_MAP = { '05' => FULLY_AUTHENTICATED_TRANSACTION, '06' => ATTEMPTED_AUTHENTICATION_TRANSACTION, '07' => NON_THREE_D_SECURE_TRANSACTION }.freeze
|
10
|
+
BRAND_TO_ECI_MAP = {
|
11
|
+
american_express: ECI_05_06_07_MAP,
|
12
|
+
dankort: ECI_05_06_07_MAP,
|
13
|
+
diners_club: ECI_05_06_07_MAP,
|
14
|
+
discover: ECI_05_06_07_MAP,
|
15
|
+
elo: ECI_05_06_07_MAP,
|
16
|
+
jcb: ECI_05_06_07_MAP,
|
17
|
+
maestro: ECI_00_01_02_MAP,
|
18
|
+
master: ECI_00_01_02_MAP,
|
19
|
+
visa: ECI_05_06_07_MAP
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
def self.map(brand, eci)
|
23
|
+
BRAND_TO_ECI_MAP.dig(brand, eci)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|