activemerchant 1.106.0 → 1.108.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +79 -0
- data/README.md +2 -2
- data/lib/active_merchant/billing/gateways/adyen.rb +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net.rb +1 -1
- data/lib/active_merchant/billing/gateways/blue_pay.rb +2 -2
- data/lib/active_merchant/billing/gateways/borgun.rb +15 -4
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +11 -9
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +20 -9
- data/lib/active_merchant/billing/gateways/clearhaus.rb +1 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +74 -21
- data/lib/active_merchant/billing/gateways/d_local.rb +17 -5
- data/lib/active_merchant/billing/gateways/decidir.rb +29 -0
- data/lib/active_merchant/billing/gateways/ebanx.rb +13 -1
- data/lib/active_merchant/billing/gateways/elavon.rb +58 -5
- data/lib/active_merchant/billing/gateways/element.rb +13 -5
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +2 -2
- data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +2 -2
- data/lib/active_merchant/billing/gateways/forte.rb +7 -6
- data/lib/active_merchant/billing/gateways/global_collect.rb +30 -24
- data/lib/active_merchant/billing/gateways/hps.rb +4 -2
- data/lib/active_merchant/billing/gateways/iats_payments.rb +31 -14
- data/lib/active_merchant/billing/gateways/iridium.rb +4 -2
- data/lib/active_merchant/billing/gateways/iveri.rb +4 -1
- data/lib/active_merchant/billing/gateways/ixopay.rb +1 -0
- data/lib/active_merchant/billing/gateways/kushki.rb +34 -5
- data/lib/active_merchant/billing/gateways/litle.rb +6 -1
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -0
- data/lib/active_merchant/billing/gateways/netaxept.rb +1 -1
- data/lib/active_merchant/billing/gateways/netbanx.rb +1 -1
- data/lib/active_merchant/billing/gateways/opp.rb +13 -7
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +4 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +44 -2
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
- data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
- data/lib/active_merchant/billing/gateways/payu_latam.rb +1 -1
- data/lib/active_merchant/billing/gateways/pin.rb +1 -1
- data/lib/active_merchant/billing/gateways/quantum.rb +1 -1
- data/lib/active_merchant/billing/gateways/realex.rb +10 -3
- data/lib/active_merchant/billing/gateways/redsys.rb +1 -1
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +1 -1
- data/lib/active_merchant/billing/gateways/so_easy_pay.rb +1 -1
- data/lib/active_merchant/billing/gateways/stripe.rb +7 -2
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +40 -6
- data/lib/active_merchant/billing/gateways/transact_pro.rb +2 -2
- data/lib/active_merchant/billing/gateways/trexle.rb +1 -1
- data/lib/active_merchant/billing/gateways/worldpay.rb +8 -6
- data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
- data/lib/active_merchant/connection.rb +40 -42
- data/lib/active_merchant/network_connection_retries.rb +10 -12
- data/lib/active_merchant/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11b837a742d2fd39e941f6aa861b3c3557fe2ddb6142b2e119c48d22e7b39749
|
4
|
+
data.tar.gz: 3aa9e72328ca32c4e84c2919dc61f3b58350d806f49fe2ea342fc9acb19a8056
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5454b152692725df9ee05bf8cfc202642ca7fb535950996d5c521c76788f0bec214f707596293185fac78d38785ef1a53924f3b99fd38137f09014c4339d92d
|
7
|
+
data.tar.gz: d724f10b88a939d856454396e0a1b9a80d975fd40d0fe2db4e8a8c0da7cdc434f4fe8c2117f86e16acb40479295d8ba766a691e6accf059973e6af1359b26387
|
data/CHANGELOG
CHANGED
@@ -2,6 +2,85 @@
|
|
2
2
|
|
3
3
|
== HEAD
|
4
4
|
|
5
|
+
== Version 1.108.0 (Jun 9, 2020)
|
6
|
+
* Cybersource: Send cavv as xid is xid is missing [pi3r] #3658
|
7
|
+
* Forte: Change default sec_code value to PPD [molbrown] #3653
|
8
|
+
* Elavon: Add merchant initiated unscheduled field [leila-alderman] #3647
|
9
|
+
* Decidir: Add aggregate data fields [leila-alderman] #3648
|
10
|
+
* Vantiv: Vantiv(Element): add option to send terminal id in transactions [cdmackeyfree] #3654
|
11
|
+
* Update supported Ruby and Rails versions [leila-alderman] #3656
|
12
|
+
* CI: Drop unused sudo: false Travis directive [olleolleolle] #3616
|
13
|
+
* PayU Latam: Prevent blank country in billing_address [britth] #3657
|
14
|
+
* DLocal: Fix address field names [molbrown] #3651
|
15
|
+
|
16
|
+
== Version 1.107.4 (Jun 2, 2020)
|
17
|
+
* Elavon: Implement true verify action [leila-alderman] #3610
|
18
|
+
* Vantiv Express: Implement true verify [leila-alderman] #3617
|
19
|
+
* Litle: Pass expiration data for basis payment method [therufs] #3606
|
20
|
+
* Stripe Payment Intents: Error handling and backwards compatibility within refund [britth] #3627
|
21
|
+
* HPS: Prevent errors when account_type or account_holder_type are nil [britth] #3628
|
22
|
+
* D Local: Handle invalid country code errors [curiousepic] #3626
|
23
|
+
* Stripe Payment Intents: Utilize execute_threed flag to determine success [britth] #3625
|
24
|
+
* Elavon: Add Level 3 fields [leila-alderman] #3632
|
25
|
+
* CyberSource: Stored Credential fixes [curiousepic] #3624
|
26
|
+
* CyberSource: Fix invalid and missing field tests [curiousepic] #3634
|
27
|
+
* CyberSource: Pass stored credentials with purchase [curiousepic] #3636
|
28
|
+
* Mercado Pago: Add payment_method_option_id field [schwarzgeist] #3635
|
29
|
+
* Stripe: Provide error when attempting an authorize with ACH [britth] #3633
|
30
|
+
* EBANX: Send original order id as merchant_payment_code metadata [miguelxpn] #3637
|
31
|
+
* Element: Add card_present_code field [schwarzgeist] #3623
|
32
|
+
* Orbital: Add support for Level 3 fields [leila-alderman] #3639
|
33
|
+
* Firstdata: Strip newline characters from address [bittercoder] #3643
|
34
|
+
* Forte: add sec_code attribute for echeck [wsmoak] #3640
|
35
|
+
|
36
|
+
== Version 1.107.3 (May 8, 2020)
|
37
|
+
* Realex: Ignore IPv6 unsupported addresses [elfassy] #3622
|
38
|
+
* Cybersource: Set partnerSolutionID after the business rules, fixes 500 error [pi3r] #3621
|
39
|
+
|
40
|
+
== Version 1.107.2 (May 7, 2020)
|
41
|
+
* Cybersource: Send a specific card brand commerceIndicator for 3DS [pi3r] #3620
|
42
|
+
* Cybersource: Send application_id as partnerSolutionID [pi3r] #3620
|
43
|
+
* Iridium: Localize zero-decimal currencies [chinhle23] #3587
|
44
|
+
* iVeri: Fix `verify` action [chinhle23] #3588
|
45
|
+
* Ixopay: Properly support three-decimal currencies [chinhle23] #3589
|
46
|
+
* Kushki: support `auth` and `capture` [therufs] #3591
|
47
|
+
* PaymentExpress: Update references to Windcave to reflect rebranding [britth] #3595
|
48
|
+
* Decidir: Improve handling of error responses from the gateway [naashton] #3594
|
49
|
+
* CyberSource: Added support for MerchantInformation CyberSource-specific fields [apfranzen] #3592
|
50
|
+
* ePay: Send unique order ids for remote tests [curiousepic] #3593
|
51
|
+
* Checkout V2: Send more informative error messages for 4xx errors [britth] #3601
|
52
|
+
* Elavon: Add ssl_dynamic_dba field [apfranzen] #3600
|
53
|
+
* iATS Payments: Update gateway to v3 and add support for additional GSFs [naashton] #3599
|
54
|
+
* Remove deprecated `rubyforge_project` attribute and tidy up unit test output [fatcatt316] #3598
|
55
|
+
* Elavon: Cleanup inadvertant field removal (avs_address) in #3600 [apfranzen] #3602
|
56
|
+
* EBANX: Fix transaction amount for verify transaction [miguelxpn] #3603
|
57
|
+
* iATS Payments: Update gateway to accept `email`, `phone`, and `country` fields [naashton] #3607
|
58
|
+
* Braintree: Fix response for failed refunds when falling back to voids [jasonwebster] #3608
|
59
|
+
* Worldpay: Fix response for failed refunds when falling back to voids [jasonwebster] #3609
|
60
|
+
* iATS Payments: Add support for Customer Code payment method [molbrown] #3611
|
61
|
+
* HPS: Add Google Pay support [MSmedal] #3597
|
62
|
+
* Adyen: Parse appropriate message for 3DS2 authorization calls [britth] #3619
|
63
|
+
* CyberSource: Add error details response fields [schwarzgeist] #3629
|
64
|
+
|
65
|
+
== Version 1.107.1 (Apr 1, 2020)
|
66
|
+
* Add `allowed_push_host` to gemspec [mdeloupy]
|
67
|
+
|
68
|
+
== Version 1.107.0 (Apr 1, 2020)
|
69
|
+
* Stripe Payment Intents: Early return failed `payment_methods` response [chinhle23] #3570
|
70
|
+
* Borgun: Support `passengerItineraryData` [therufs] #3572
|
71
|
+
* Ingenico GlobalCollect: support optional `requires_approval` field [fatcatt316] #3571
|
72
|
+
* CenPOS: Update failing remote tests [britth] #3575
|
73
|
+
* Realex: Update remote tests [britth] #3576
|
74
|
+
* FirstData e4 v27: Properly tag stored credential initiation field in request [britth] #3578
|
75
|
+
* Orbital: Fix stored credentials [chinhle23] #3579
|
76
|
+
* Acapture(Opp): Update gateway credentials [molbrown] #3574
|
77
|
+
* Ingenico GlobalCollect: support `requires_approval` field [fatcatt316] #3577
|
78
|
+
* CyberSource: Fix `void` for `purchase` transactions [chinhle23] #3581
|
79
|
+
* Checkout V2: Begin to add support for using network tokens for transactions. [arbianchi] #3580
|
80
|
+
* Opp: Update remote test fixtures [ccarruitero] #3582
|
81
|
+
* Optimal Payment: Add support for store [britth] #3585
|
82
|
+
* SecurePay Australia : Update test URL (#3586)
|
83
|
+
|
5
84
|
== Version 1.106.0 (Mar 10, 2020)
|
6
85
|
* PayJunctionV2: Send billing address in `auth` and `purchase` transactions [naashton] #3538
|
7
86
|
* Adyen: Fix some remote tests [curiousepic] #3541
|
data/README.md
CHANGED
@@ -183,7 +183,7 @@ The [ActiveMerchant Wiki](https://github.com/activemerchant/active_merchant/wiki
|
|
183
183
|
* [Paybox Direct](http://www.paybox.com/) - FR
|
184
184
|
* [Payeezy](https://developer.payeezy.com/) - CA, US
|
185
185
|
* [Payex](http://payex.com/) - DK, FI, NO, SE
|
186
|
-
* [PaymentExpress](
|
186
|
+
* [Windcave (formerly PaymentExpress)](https://www.windcave.com/) - AU, CA, DE, ES, FR, GB, HK, IE, MY, NL, NZ, SG, US, ZA
|
187
187
|
* [PAYMILL](https://paymill.com) - AD, AT, BE, BG, CH, CY, CZ, DE, DK, EE, ES, FI, FO, FR, GB, GI, GR, HU, IE, IL, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE, SI, SK, TR, VA
|
188
188
|
* [PayPal Express Checkout](https://www.paypal.com/webapps/mpp/express-checkout) - US, CA, SG, AU
|
189
189
|
* [PayPal Express Checkout (UK)](https://www.paypal.com/uk/webapps/mpp/express-checkout) - GB
|
@@ -244,4 +244,4 @@ Functionality or APIs that are deprecated will be marked as such. Deprecated fun
|
|
244
244
|
|
245
245
|
## Ruby and Rails compatibility policies
|
246
246
|
|
247
|
-
Because Active Merchant is a payment library, it needs to take security seriously. For this reason, Active Merchant guarantees compatibility only with actively supported versions of Ruby and Rails. At the time of this writing, that means that Ruby 2.
|
247
|
+
Because Active Merchant is a payment library, it needs to take security seriously. For this reason, Active Merchant guarantees compatibility only with actively supported versions of Ruby and Rails. At the time of this writing, that means that Ruby 2.5+ and Rails 5.0+ are supported.
|
@@ -549,7 +549,7 @@ module ActiveMerchant #:nodoc:
|
|
549
549
|
end
|
550
550
|
|
551
551
|
def message_from(action, response)
|
552
|
-
return authorize_message_from(response) if
|
552
|
+
return authorize_message_from(response) if %w(authorise authorise3d authorise3ds2).include?(action.to_s)
|
553
553
|
|
554
554
|
response['response'] || response['message'] || response['result']
|
555
555
|
end
|
@@ -488,7 +488,7 @@ module ActiveMerchant
|
|
488
488
|
|
489
489
|
def add_swipe_data(xml, credit_card)
|
490
490
|
TRACKS.each do |key, regex|
|
491
|
-
if regex.match(credit_card.track_data)
|
491
|
+
if regex.match?(credit_card.track_data)
|
492
492
|
@valid_track_data = true
|
493
493
|
xml.payment do
|
494
494
|
xml.trackData do
|
@@ -382,9 +382,9 @@ module ActiveMerchant #:nodoc:
|
|
382
382
|
end
|
383
383
|
elsif message == 'Missing ACCOUNT_ID'
|
384
384
|
message = 'The merchant login ID or password is invalid'
|
385
|
-
elsif
|
385
|
+
elsif /Approved/.match?(message)
|
386
386
|
message = 'This transaction has been approved'
|
387
|
-
elsif
|
387
|
+
elsif /Expired/.match?(message)
|
388
388
|
message = 'The credit card has expired'
|
389
389
|
end
|
390
390
|
message
|
@@ -34,7 +34,7 @@ module ActiveMerchant #:nodoc:
|
|
34
34
|
post[:TransType] = '5'
|
35
35
|
add_invoice(post, money, options)
|
36
36
|
add_payment_method(post, payment)
|
37
|
-
commit('authonly', post)
|
37
|
+
commit('authonly', post, options)
|
38
38
|
end
|
39
39
|
|
40
40
|
def capture(money, authorization, options={})
|
@@ -125,12 +125,12 @@ module ActiveMerchant #:nodoc:
|
|
125
125
|
response
|
126
126
|
end
|
127
127
|
|
128
|
-
def commit(action, post)
|
128
|
+
def commit(action, post, options={})
|
129
129
|
post[:Version] = '1000'
|
130
130
|
post[:Processor] = @options[:processor]
|
131
131
|
post[:MerchantID] = @options[:merchant_id]
|
132
132
|
|
133
|
-
request = build_request(action, post)
|
133
|
+
request = build_request(action, post, options)
|
134
134
|
raw = ssl_post(url(action), request, headers)
|
135
135
|
pairs = parse(raw)
|
136
136
|
success = success_from(pairs)
|
@@ -180,7 +180,7 @@ module ActiveMerchant #:nodoc:
|
|
180
180
|
}
|
181
181
|
end
|
182
182
|
|
183
|
-
def build_request(action, post)
|
183
|
+
def build_request(action, post, options={})
|
184
184
|
mode = action == 'void' ? 'cancel' : 'get'
|
185
185
|
xml = Builder::XmlMarkup.new indent: 18
|
186
186
|
xml.instruct!(:xml, version: '1.0', encoding: 'utf-8')
|
@@ -188,11 +188,22 @@ module ActiveMerchant #:nodoc:
|
|
188
188
|
post.each do |field, value|
|
189
189
|
xml.tag!(field, value)
|
190
190
|
end
|
191
|
+
build_airline_xml(xml, options[:passenger_itinerary_data]) if options[:passenger_itinerary_data]
|
191
192
|
end
|
192
193
|
inner = CGI.escapeHTML(xml.target!)
|
193
194
|
envelope(mode).sub(/{{ :body }}/, inner)
|
194
195
|
end
|
195
196
|
|
197
|
+
def build_airline_xml(xml, airline_data)
|
198
|
+
xml.tag!('PassengerItineraryData') do
|
199
|
+
xml.tag!('A1') do
|
200
|
+
airline_data.each do |field, value|
|
201
|
+
xml.tag!(field, value)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
196
207
|
def envelope(mode)
|
197
208
|
<<-EOS
|
198
209
|
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:aut="http://Borgun/Heimir/pub/ws/Authorization">
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_merchant/billing/gateways/braintree/braintree_common'
|
2
|
+
require 'active_support/core_ext/array/extract_options'
|
2
3
|
|
3
4
|
begin
|
4
5
|
require 'braintree'
|
@@ -98,10 +99,13 @@ module ActiveMerchant #:nodoc:
|
|
98
99
|
|
99
100
|
commit do
|
100
101
|
response = response_from_result(@braintree_gateway.transaction.refund(transaction_id, money))
|
101
|
-
return response if response.success?
|
102
|
-
return response unless options[:force_full_refund_if_unsettled]
|
103
102
|
|
104
|
-
|
103
|
+
if !response.success? && options[:force_full_refund_if_unsettled] &&
|
104
|
+
response.message =~ /#{ERROR_CODES[:cannot_refund_if_unsettled]}/
|
105
|
+
void(transaction_id)
|
106
|
+
else
|
107
|
+
response
|
108
|
+
end
|
105
109
|
end
|
106
110
|
end
|
107
111
|
|
@@ -200,12 +204,10 @@ module ActiveMerchant #:nodoc:
|
|
200
204
|
|
201
205
|
def check_customer_exists(customer_vault_id)
|
202
206
|
commit do
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
ActiveMerchant::Billing::Response.new(true, 'Customer not found', {exists: false})
|
208
|
-
end
|
207
|
+
@braintree_gateway.customer.find(customer_vault_id)
|
208
|
+
ActiveMerchant::Billing::Response.new(true, 'Customer found', {exists: true}, authorization: customer_vault_id)
|
209
|
+
rescue Braintree::NotFoundError
|
210
|
+
ActiveMerchant::Billing::Response.new(true, 'Customer not found', {exists: false})
|
209
211
|
end
|
210
212
|
end
|
211
213
|
|
@@ -102,13 +102,21 @@ module ActiveMerchant #:nodoc:
|
|
102
102
|
|
103
103
|
def add_payment_method(post, payment_method, options)
|
104
104
|
post[:source] = {}
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
105
|
+
if payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :network_token
|
106
|
+
post[:source][:type] = 'network_token'
|
107
|
+
post[:source][:token] = payment_method.number
|
108
|
+
post[:source][:token_type] = payment_method.brand == 'visa' ? 'vts' : 'mdes'
|
109
|
+
post[:source][:cryptogram] = payment_method.payment_cryptogram
|
110
|
+
post[:source][:eci] = options[:eci] || '05'
|
111
|
+
else
|
112
|
+
post[:source][:type] = 'card'
|
113
|
+
post[:source][:name] = payment_method.name
|
114
|
+
post[:source][:number] = payment_method.number
|
115
|
+
post[:source][:cvv] = payment_method.verification_value
|
116
|
+
post[:source][:stored] = 'true' if options[:card_on_file] == true
|
117
|
+
end
|
109
118
|
post[:source][:expiry_year] = format(payment_method.year, :four_digits)
|
110
119
|
post[:source][:expiry_month] = format(payment_method.month, :two_digits)
|
111
|
-
post[:source][:stored] = 'true' if options[:card_on_file] == true
|
112
120
|
end
|
113
121
|
|
114
122
|
def add_customer_data(post, options)
|
@@ -158,7 +166,7 @@ module ActiveMerchant #:nodoc:
|
|
158
166
|
rescue ResponseError => e
|
159
167
|
raise unless e.response.code.to_s =~ /4\d\d/
|
160
168
|
|
161
|
-
response = parse(e.response.body)
|
169
|
+
response = parse(e.response.body, error: e.response)
|
162
170
|
end
|
163
171
|
|
164
172
|
succeeded = success_from(response)
|
@@ -216,13 +224,16 @@ module ActiveMerchant #:nodoc:
|
|
216
224
|
response['source'] && response['source']['cvv_check'] ? CVVResult.new(response['source']['cvv_check']) : nil
|
217
225
|
end
|
218
226
|
|
219
|
-
def parse(body)
|
227
|
+
def parse(body, error: nil)
|
220
228
|
JSON.parse(body)
|
221
229
|
rescue JSON::ParserError
|
222
|
-
{
|
230
|
+
response = {
|
231
|
+
'error_type' => error&.code,
|
223
232
|
'message' => 'Invalid JSON response received from Checkout.com Unified Payments Gateway. Please contact Checkout.com if you continue to receive this message.',
|
224
233
|
'raw_response' => scrub(body)
|
225
234
|
}
|
235
|
+
response['error_codes'] = [error&.message] if error&.message
|
236
|
+
response
|
226
237
|
end
|
227
238
|
|
228
239
|
def success_from(response)
|
@@ -235,7 +246,7 @@ module ActiveMerchant #:nodoc:
|
|
235
246
|
elsif response['error_type']
|
236
247
|
response['error_type'] + ': ' + response['error_codes'].first
|
237
248
|
else
|
238
|
-
response['response_summary'] || response['response_code'] || response['status'] || 'Unable to read error message'
|
249
|
+
response['response_summary'] || response['response_code'] || response['status'] || response['message'] || 'Unable to read error message'
|
239
250
|
end
|
240
251
|
end
|
241
252
|
|
@@ -206,7 +206,7 @@ module ActiveMerchant #:nodoc:
|
|
206
206
|
|
207
207
|
def generate_signature(body)
|
208
208
|
key = OpenSSL::PKey::RSA.new(@options[:private_key])
|
209
|
-
hex = key.sign(OpenSSL::Digest.new('sha256'), body).
|
209
|
+
hex = key.sign(OpenSSL::Digest.new('sha256'), body).unpack1('H*')
|
210
210
|
|
211
211
|
"#{@options[:signing_key]} RS256-hex #{hex}"
|
212
212
|
end
|
@@ -25,8 +25,16 @@ module ActiveMerchant #:nodoc:
|
|
25
25
|
self.live_url = 'https://ics2wsa.ic3.com/commerce/1.x/transactionProcessor'
|
26
26
|
|
27
27
|
# Schema files can be found here: https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/
|
28
|
-
TEST_XSD_VERSION = '1.
|
29
|
-
PRODUCTION_XSD_VERSION = '1.
|
28
|
+
TEST_XSD_VERSION = '1.164'
|
29
|
+
PRODUCTION_XSD_VERSION = '1.164'
|
30
|
+
ECI_BRAND_MAPPING = {
|
31
|
+
visa: 'vbv',
|
32
|
+
master: 'spa',
|
33
|
+
american_express: 'aesk',
|
34
|
+
jcb: 'js',
|
35
|
+
discover: 'pb',
|
36
|
+
}.freeze
|
37
|
+
DEFAULT_COLLECTION_INDICATOR = 2
|
30
38
|
|
31
39
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :dankort, :maestro, :elo]
|
32
40
|
self.supported_countries = %w(US BR CA CN DK FI FR DE IN JP MX NO SE GB SG LB PK)
|
@@ -272,6 +280,8 @@ module ActiveMerchant #:nodoc:
|
|
272
280
|
add_business_rules_data(xml, creditcard_or_reference, options)
|
273
281
|
add_stored_credential_options(xml, options)
|
274
282
|
add_issuer_additional_data(xml, options)
|
283
|
+
add_merchant_description(xml, options)
|
284
|
+
add_partner_solution_id(xml)
|
275
285
|
|
276
286
|
xml.target!
|
277
287
|
end
|
@@ -298,6 +308,9 @@ module ActiveMerchant #:nodoc:
|
|
298
308
|
add_capture_service(xml, request_id, request_token)
|
299
309
|
add_business_rules_data(xml, authorization, options)
|
300
310
|
add_issuer_additional_data(xml, options)
|
311
|
+
add_merchant_description(xml, options)
|
312
|
+
add_partner_solution_id(xml)
|
313
|
+
|
301
314
|
xml.target!
|
302
315
|
end
|
303
316
|
|
@@ -314,8 +327,12 @@ module ActiveMerchant #:nodoc:
|
|
314
327
|
add_threeds_services(xml, options)
|
315
328
|
add_payment_network_token(xml) if network_tokenization?(payment_method_or_reference)
|
316
329
|
add_business_rules_data(xml, payment_method_or_reference, options) unless options[:pinless_debit_card]
|
330
|
+
add_stored_credential_options(xml, options)
|
317
331
|
end
|
332
|
+
|
318
333
|
add_issuer_additional_data(xml, options)
|
334
|
+
add_merchant_description(xml, options)
|
335
|
+
add_partner_solution_id(xml)
|
319
336
|
|
320
337
|
xml.target!
|
321
338
|
end
|
@@ -325,7 +342,8 @@ module ActiveMerchant #:nodoc:
|
|
325
342
|
options[:order_id] = order_id
|
326
343
|
|
327
344
|
xml = Builder::XmlMarkup.new indent: 2
|
328
|
-
|
345
|
+
case action
|
346
|
+
when 'capture', 'purchase'
|
329
347
|
add_mdd_fields(xml, options)
|
330
348
|
add_void_service(xml, request_id, request_token)
|
331
349
|
else
|
@@ -334,6 +352,8 @@ module ActiveMerchant #:nodoc:
|
|
334
352
|
add_auth_reversal_service(xml, request_id, request_token)
|
335
353
|
end
|
336
354
|
add_issuer_additional_data(xml, options)
|
355
|
+
add_partner_solution_id(xml)
|
356
|
+
|
337
357
|
xml.target!
|
338
358
|
end
|
339
359
|
|
@@ -344,6 +364,7 @@ module ActiveMerchant #:nodoc:
|
|
344
364
|
xml = Builder::XmlMarkup.new indent: 2
|
345
365
|
add_purchase_data(xml, money, true, options)
|
346
366
|
add_credit_service(xml, request_id, request_token)
|
367
|
+
add_partner_solution_id(xml)
|
347
368
|
|
348
369
|
xml.target!
|
349
370
|
end
|
@@ -355,6 +376,7 @@ module ActiveMerchant #:nodoc:
|
|
355
376
|
add_mdd_fields(xml, options)
|
356
377
|
add_credit_service(xml)
|
357
378
|
add_issuer_additional_data(xml, options)
|
379
|
+
add_merchant_description(xml, options)
|
358
380
|
|
359
381
|
xml.target!
|
360
382
|
end
|
@@ -458,6 +480,7 @@ module ActiveMerchant #:nodoc:
|
|
458
480
|
xml.tag! 'clientLibrary', 'Ruby Active Merchant'
|
459
481
|
xml.tag! 'clientLibraryVersion', VERSION
|
460
482
|
xml.tag! 'clientEnvironment', RUBY_PLATFORM
|
483
|
+
|
461
484
|
add_merchant_descriptor(xml, options)
|
462
485
|
end
|
463
486
|
|
@@ -469,6 +492,18 @@ module ActiveMerchant #:nodoc:
|
|
469
492
|
end
|
470
493
|
end
|
471
494
|
|
495
|
+
def add_merchant_description(xml, options)
|
496
|
+
return unless options[:merchant_descriptor_name] || options[:merchant_descriptor_address1] || options[:merchant_descriptor_locality]
|
497
|
+
|
498
|
+
xml.tag! 'merchantInformation' do
|
499
|
+
xml.tag! 'merchantDescriptor' do
|
500
|
+
xml.tag! 'name', options[:merchant_descriptor_name] if options[:merchant_descriptor_name]
|
501
|
+
xml.tag! 'address1', options[:merchant_descriptor_address1] if options[:merchant_descriptor_address1]
|
502
|
+
xml.tag! 'locality', options[:merchant_descriptor_locality] if options[:merchant_descriptor_locality]
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
472
507
|
def add_purchase_data(xml, money = 0, include_grand_total = false, options={})
|
473
508
|
xml.tag! 'purchaseTotals' do
|
474
509
|
xml.tag! 'currency', options[:currency] || currency(money)
|
@@ -580,9 +615,12 @@ module ActiveMerchant #:nodoc:
|
|
580
615
|
xml.tag!('cavvAlgorithm', threeds_2_options[:cavv_algorithm]) if threeds_2_options[:cavv_algorithm]
|
581
616
|
xml.tag!('paSpecificationVersion', threeds_2_options[:version]) if threeds_2_options[:version]
|
582
617
|
xml.tag!('directoryServerTransactionID', threeds_2_options[:ds_transaction_id]) if threeds_2_options[:ds_transaction_id]
|
583
|
-
xml.tag!('commerceIndicator', options[:commerce_indicator]
|
618
|
+
xml.tag!('commerceIndicator', options[:commerce_indicator] || ECI_BRAND_MAPPING[card_brand(payment_method).to_sym])
|
584
619
|
xml.tag!('eciRaw', threeds_2_options[:eci]) if threeds_2_options[:eci]
|
585
|
-
|
620
|
+
|
621
|
+
xid = threeds_2_options[:xid] || threeds_2_options[:cavv]
|
622
|
+
xml.tag!('xid', xid) if xid
|
623
|
+
|
586
624
|
xml.tag!('veresEnrolled', threeds_2_options[:enrolled]) if threeds_2_options[:enrolled]
|
587
625
|
xml.tag!('paresStatus', threeds_2_options[:authentication_response_status]) if threeds_2_options[:authentication_response_status]
|
588
626
|
end
|
@@ -592,12 +630,13 @@ module ActiveMerchant #:nodoc:
|
|
592
630
|
|
593
631
|
xml.tag! 'ucaf' do
|
594
632
|
xml.tag!('authenticationData', options[:three_d_secure][:cavv])
|
595
|
-
xml.tag!('collectionIndicator', options[:collection_indicator]
|
633
|
+
xml.tag!('collectionIndicator', options[:collection_indicator] || DEFAULT_COLLECTION_INDICATOR)
|
596
634
|
end
|
597
635
|
end
|
598
636
|
|
599
637
|
def stored_credential_commerce_indicator(options)
|
600
638
|
return unless options[:stored_credential]
|
639
|
+
|
601
640
|
return if options[:stored_credential][:initial_transaction]
|
602
641
|
|
603
642
|
case options[:stored_credential][:reason_type]
|
@@ -613,26 +652,28 @@ module ActiveMerchant #:nodoc:
|
|
613
652
|
def add_auth_network_tokenization(xml, payment_method, options)
|
614
653
|
return unless network_tokenization?(payment_method)
|
615
654
|
|
616
|
-
|
655
|
+
brand = card_brand(payment_method).to_sym
|
656
|
+
|
657
|
+
case brand
|
617
658
|
when :visa
|
618
659
|
xml.tag! 'ccAuthService', {'run' => 'true'} do
|
619
660
|
xml.tag!('cavv', payment_method.payment_cryptogram)
|
620
|
-
xml.tag!('commerceIndicator',
|
661
|
+
xml.tag!('commerceIndicator', ECI_BRAND_MAPPING[brand])
|
621
662
|
xml.tag!('xid', payment_method.payment_cryptogram)
|
622
663
|
end
|
623
664
|
when :master
|
624
665
|
xml.tag! 'ucaf' do
|
625
666
|
xml.tag!('authenticationData', payment_method.payment_cryptogram)
|
626
|
-
xml.tag!('collectionIndicator',
|
667
|
+
xml.tag!('collectionIndicator', DEFAULT_COLLECTION_INDICATOR)
|
627
668
|
end
|
628
669
|
xml.tag! 'ccAuthService', {'run' => 'true'} do
|
629
|
-
xml.tag!('commerceIndicator',
|
670
|
+
xml.tag!('commerceIndicator', ECI_BRAND_MAPPING[brand])
|
630
671
|
end
|
631
672
|
when :american_express
|
632
673
|
cryptogram = Base64.decode64(payment_method.payment_cryptogram)
|
633
674
|
xml.tag! 'ccAuthService', {'run' => 'true'} do
|
634
675
|
xml.tag!('cavv', Base64.encode64(cryptogram[0...20]))
|
635
|
-
xml.tag!('commerceIndicator',
|
676
|
+
xml.tag!('commerceIndicator', ECI_BRAND_MAPPING[brand])
|
636
677
|
xml.tag!('xid', Base64.encode64(cryptogram[20...40]))
|
637
678
|
end
|
638
679
|
end
|
@@ -783,14 +824,16 @@ module ActiveMerchant #:nodoc:
|
|
783
824
|
def add_stored_credential_options(xml, options={})
|
784
825
|
return unless options[:stored_credential]
|
785
826
|
|
786
|
-
if options[:stored_credential][:
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
827
|
+
xml.tag! 'subsequentAuth', 'true' if options[:stored_credential][:initiator] == 'merchant'
|
828
|
+
xml.tag! 'subsequentAuthFirst', 'true' if options[:stored_credential][:initial_transaction]
|
829
|
+
xml.tag! 'subsequentAuthTransactionID', options[:stored_credential][:network_transaction_id] if options[:stored_credential][:initiator] == 'merchant'
|
830
|
+
xml.tag! 'subsequentAuthStoredCredential', 'true' if options[:stored_credential][:initiator] == 'cardholder' && !options[:stored_credential][:initial_transaction] || options[:stored_credential][:initiator] == 'merchant' && options[:stored_credential][:reason_type] == 'unscheduled'
|
831
|
+
end
|
832
|
+
|
833
|
+
def add_partner_solution_id(xml)
|
834
|
+
return unless application_id
|
835
|
+
|
836
|
+
xml.tag!('partnerSolutionID', application_id)
|
794
837
|
end
|
795
838
|
|
796
839
|
# Where we actually build the full SOAP request using builder
|
@@ -834,7 +877,7 @@ module ActiveMerchant #:nodoc:
|
|
834
877
|
end
|
835
878
|
|
836
879
|
success = success?(response)
|
837
|
-
message = response
|
880
|
+
message = message_from(response)
|
838
881
|
|
839
882
|
authorization = success ? authorization_from(response, action, amount, options) : nil
|
840
883
|
|
@@ -873,7 +916,7 @@ module ActiveMerchant #:nodoc:
|
|
873
916
|
if node.has_elements?
|
874
917
|
node.elements.each { |e| parse_element(reply, e) }
|
875
918
|
else
|
876
|
-
if node.parent.name
|
919
|
+
if /item/.match?(node.parent.name)
|
877
920
|
parent = node.parent.name
|
878
921
|
parent += '_' + node.parent.attributes['id'] if node.parent.attributes['id']
|
879
922
|
parent += '_'
|
@@ -901,6 +944,16 @@ module ActiveMerchant #:nodoc:
|
|
901
944
|
def success?(response)
|
902
945
|
response[:decision] == @@decision_codes[:accept]
|
903
946
|
end
|
947
|
+
|
948
|
+
def message_from(response)
|
949
|
+
if response[:reasonCode] == '101' && response[:missingField]
|
950
|
+
"#{response[:message]}: #{response[:missingField]}"
|
951
|
+
elsif response[:reasonCode] == '102' && response[:invalidField]
|
952
|
+
"#{response[:message]}: #{response[:invalidField]}"
|
953
|
+
else
|
954
|
+
response[:message]
|
955
|
+
end
|
956
|
+
end
|
904
957
|
end
|
905
958
|
end
|
906
959
|
end
|