activemerchant 1.124.0 → 1.125.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +85 -0
- data/lib/active_merchant/billing/check.rb +5 -8
- data/lib/active_merchant/billing/credit_card.rb +10 -0
- data/lib/active_merchant/billing/gateway.rb +1 -1
- 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/cyber_source.rb +11 -3
- data/lib/active_merchant/billing/gateways/d_local.rb +4 -5
- 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 +6 -3
- data/lib/active_merchant/billing/gateways/element.rb +20 -2
- data/lib/active_merchant/billing/gateways/global_collect.rb +106 -16
- data/lib/active_merchant/billing/gateways/ipg.rb +416 -0
- data/lib/active_merchant/billing/gateways/kushki.rb +7 -0
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +3 -1
- data/lib/active_merchant/billing/gateways/mundipagg.rb +8 -6
- data/lib/active_merchant/billing/gateways/nmi.rb +2 -1
- data/lib/active_merchant/billing/gateways/orbital.rb +17 -2
- data/lib/active_merchant/billing/gateways/pay_trace.rb +1 -1
- data/lib/active_merchant/billing/gateways/payflow.rb +1 -1
- data/lib/active_merchant/billing/gateways/paymentez.rb +9 -2
- data/lib/active_merchant/billing/gateways/paysafe.rb +41 -5
- data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -1
- 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/safe_charge.rb +1 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +20 -10
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +37 -3
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +20 -6
- data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +181 -64
- data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f8d0ad7bb54e228b44738e6cf324034467970e6709047a7f799dd7d3276998c
|
4
|
+
data.tar.gz: 96ab0828793d536f7df925fe962444c1cc0c48d129de54c19d40c81145ed1d11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a31f43e0702edeb5727c61285c54afeecc5accc6c9f89134966228fe9c08369f9918890ff25cda85ec863f3cda2bd1e2e6dde8f4eed1254ed6d520f37067dcd
|
7
|
+
data.tar.gz: 144dc89e223d28ceed1399b50d15116d169dc056f878bb9ba9ed477e4c141fde2c2bc25a882610e4295fa3a25fc8f63800034352b77eb3a370718ea64d017665
|
data/CHANGELOG
CHANGED
@@ -1,7 +1,92 @@
|
|
1
|
+
|
1
2
|
= ActiveMerchant CHANGELOG
|
2
3
|
|
3
4
|
== HEAD
|
4
5
|
|
6
|
+
== Version 1.125.0 (January 20, 2022)
|
7
|
+
* Wompi: support gateway [therufs] #4173
|
8
|
+
* Stripe Payment Intents: Add setup_purchase [aenand] #4178
|
9
|
+
* Ipg: Add new gateway [ajawadmirza] #4171
|
10
|
+
* Worldpay: Adding support for google pay and apple pay [cristian] #4180
|
11
|
+
* Worldpay: Adding scrubbing for network token transactions [cristian] #4181
|
12
|
+
* SafeCharge: Add sg_NotUseCVV field [ajawadmirza] #4177
|
13
|
+
* PayULatam: Correctly map maestro and condensa card types [dsmcclain] #4182
|
14
|
+
* StripePaymentIntents: Refactor response for setup_purchase [aenand] #4183
|
15
|
+
* Wompi: cast error messages to JSON [therufs] #4186
|
16
|
+
* NMI: Omit initial_transaction_id for CIT [aenand] #4189
|
17
|
+
* Priority: Support Priority Payment Systems gateway [jessiagee] #4166
|
18
|
+
* GlobalCollect: Support for Lodging Data [naashton] #4190
|
19
|
+
* IPG: Add support for sub-merchant and recurring type fields [ajawadmirza] # 4188
|
20
|
+
* Wompi: Support `installments` option [therufs] #4192
|
21
|
+
* Stripe PI: add support for `fulfillment_date` and `event_type` [dsmcclain] #4193
|
22
|
+
* Paysafe: Adjust logic for sending 3DS field [meagabeth] #4194
|
23
|
+
* Priority: Fix unit test cases [ajawadmirza] #4195
|
24
|
+
* EBANX: New Gateway Specific Receiver [spreedly-kledoux] #4198
|
25
|
+
* Wompi: Don't send CVV field if no CVV provided [therufs] #4199
|
26
|
+
* Worldpay: cleaning order_id according to worldpay rules [cristian] #4197
|
27
|
+
* Paysafe: Concatenate credentials for headers [meagabeth] #4201
|
28
|
+
* Stripe Payment Intents: Add metadata to setup_purchase [aenand] #4202
|
29
|
+
* Priority: Add gateway standard changes [ajawadmirza] #4200
|
30
|
+
* IPG: Add support for payment by token [ajawadmirza] #4191
|
31
|
+
* Element (Vantiv Express): Add support for general credit [dsmcclain] #4203
|
32
|
+
* Worldpay: Update supported countries list, currencies [jherreraa] #4207
|
33
|
+
* StripePI: Adding countries available. [gasb150] #4208
|
34
|
+
* Orbital: Adding google pay payment tests for Orbital. [ajawadmirza] #4205
|
35
|
+
* Bug: Fixing supported countries method when there is inheritance involved [cristian] #4211
|
36
|
+
* Mundipagg: Update success method [ajawadmirza] #4210
|
37
|
+
* Worldpay: Add support for Visa Direct Fast Funds Credit [dsmcclain] #4212
|
38
|
+
* Paysafe: Add support for stored credentials [meagabeth] #4214
|
39
|
+
* Worldpay: Adding missing countries to supported countries [cristian] #4213
|
40
|
+
* Update institution numbers for Canadian banks [therufs] #4216
|
41
|
+
* Worldpay: Set default eCommerce indicator for EMVCO network tokens [shasum] #4215
|
42
|
+
* Update handling routing numbers for Canadian banks [therufs] #4217
|
43
|
+
* Stripe: API version updated [jherreraa] #4209
|
44
|
+
* Mercado Pago: Update verify method [ajawadmirza] #4219
|
45
|
+
* DLocal: Set API Version [gasb150] #4222
|
46
|
+
* Wompi: Add support for Authorize and Capture [rachelkirk] #4218
|
47
|
+
* Priority: Update source and billing address checks [jessiagee] #4220
|
48
|
+
* Pin Payments: Add support for `diners_club`, `discover`, and `jcb` cardtypes [montdidier] #4142
|
49
|
+
* USA ePay: Add store method [ajawadmirza] #4224
|
50
|
+
* IPG: Quick fix to remove warning [ajawadmirza] #4225
|
51
|
+
* Remove YAML warning on load_fixtures_method [jherreraa] #4226
|
52
|
+
* Worldpay: Add support for tokenizing payment methods with transaction identifiers [dsmcclain] #4227
|
53
|
+
* USA ePay: Update implementation to send valid authorization [ajawadmirza] #4231
|
54
|
+
* USA ePay: Add store test, update authorize param [jessiagee] #4232
|
55
|
+
* Stripe: Update destination test account [jherreraa] #4234
|
56
|
+
* Add skip_response option on request check for commit stubs [cristian] #4223
|
57
|
+
* Pin Payments: Add support for `void` and New Zealand to supported countries. [montdidier] #4144
|
58
|
+
* Wompi: Update authorization in `capture` method. [rachelkirk] #4238
|
59
|
+
* IPG: Update authorization to support `store` method token. [ajawadmirza] #4233
|
60
|
+
* Paymentez: Update card mappings [ajawadmirza] #4237
|
61
|
+
* Priority: Update parsing for error messages [jessiagee] #4245
|
62
|
+
* GlobalCollect: Support for Airline Data [naashton] #4187
|
63
|
+
* IPG: Add `tpv_error_code` and `tpv_error_msg` fields [ajawadmirza] #4241
|
64
|
+
* StripePI: Set restriction for Apple/Google Pay [jherreraa] #4247
|
65
|
+
* Cashnet: support multiple itemcodes and amounts [peteroas] #4243
|
66
|
+
* IPG: Send default currency in `verify` and two digit `ExpMonth` [ajawadmirza] #4244
|
67
|
+
* Stripe: Add remote tests set up to avoid exceed the max external accounts limit [jherreraa] #4239
|
68
|
+
* Stripe: Add support for `radar_options: skip_rules` [dsmcclain] #4250
|
69
|
+
* CyberSource: Add `user_po`, `taxable`, `national_tax_indicator`, `tax_amount`, and `national_tax` fields [ajawadmirza] #4251
|
70
|
+
* Kushki: Add support for `metadata` [rachelkirk] #4253
|
71
|
+
* IPG: Add `redact` operation [ajawadmirza] #4254
|
72
|
+
* Wompi: Update sandbox and production endpoints [rachelkirk] #4255
|
73
|
+
* Orbital: Add `sca_merchant_initiated` operation [ajawadmirza] #4256
|
74
|
+
* Cashnet: convert amounts to integers for proper gateway handling [peteroas] #2207
|
75
|
+
* PayTrace: Add `unstore` operation [ajawadmirza] #4262
|
76
|
+
* Decidir Plus: Add gateway adapter [naashton] #4264
|
77
|
+
* CheckoutV2: Add support for Apple Pay and Google Pay tokens [AMHOL] #4235
|
78
|
+
* Decidir Plus: Update payment reference [naashton] #4271
|
79
|
+
* Paysafe: Update redact method [meagabeth] #4269
|
80
|
+
* CyberSource: Add `line_items` field in authorize method [ajawadmirza] #4268
|
81
|
+
* CheckoutV2: Support processing channel and marketplace sub entity ID [AMHOL] #4236
|
82
|
+
* Elavon: `third_party_token` bug fix [rachelkirk] #4273
|
83
|
+
* Decidir Plus: Add `sub_payments` field [naashton] #4274
|
84
|
+
* Pin Payments: Add `unstore` support [montdidier] #4276
|
85
|
+
* Orbital: Add support for $0 verify [javierpedrozaing] #4275
|
86
|
+
* Update inline documentation with all supported cardtypes [ali-hassan] #4283
|
87
|
+
* PayWay: Update endpoints, response code [jessiagee] #4281
|
88
|
+
* CyberSource: Add `line_items` for purchase [ajawadmirza] #4282
|
89
|
+
|
5
90
|
== Version 1.124.0 (October 28th, 2021)
|
6
91
|
* Worldpay: Add Support for Submerchant Data on Worldpay [almalee24] #4147
|
7
92
|
* dlocal: Add device_id and ip to payer object and add additional_data [aenand] #4116
|
@@ -14,13 +14,13 @@ module ActiveMerchant #:nodoc:
|
|
14
14
|
attr_accessor :institution_number, :transit_number
|
15
15
|
|
16
16
|
# Canadian Institution Numbers
|
17
|
-
#
|
17
|
+
# Partial list found here: https://en.wikipedia.org/wiki/Routing_number_(Canada)
|
18
18
|
CAN_INSTITUTION_NUMBERS = %w(
|
19
|
-
001 002 003 004
|
20
|
-
309 310 315 320
|
19
|
+
001 002 003 004 006 010 016 030 039 117 127 177 219 245 260 269 270 308
|
20
|
+
309 310 315 320 338 340 509 540 608 614 623 809 815 819 828 829 837 839
|
21
21
|
865 879 889 899 241 242 248 250 265 275 277 290 294 301 303 307 311 314
|
22
22
|
321 323 327 328 330 332 334 335 342 343 346 352 355 361 362 366 370 372
|
23
|
-
376 378 807 853
|
23
|
+
376 378 807 853 890
|
24
24
|
)
|
25
25
|
|
26
26
|
def name
|
@@ -71,11 +71,8 @@ module ActiveMerchant #:nodoc:
|
|
71
71
|
(7 * (digits[1] + digits[4] + digits[7])) +
|
72
72
|
(digits[2] + digits[5] + digits[8])) % 10
|
73
73
|
|
74
|
-
return checksum == 0
|
74
|
+
return checksum == 0 || CAN_INSTITUTION_NUMBERS.include?(routing_number[1..3])
|
75
75
|
end
|
76
|
-
|
77
|
-
return CAN_INSTITUTION_NUMBERS.include?(routing_number[0..2]) if digits.size == 8
|
78
|
-
|
79
76
|
false
|
80
77
|
end
|
81
78
|
end
|
@@ -18,6 +18,11 @@ module ActiveMerchant #:nodoc:
|
|
18
18
|
# * Dankort
|
19
19
|
# * Maestro
|
20
20
|
# * Forbrugsforeningen
|
21
|
+
# * Sodexo
|
22
|
+
# * Vr
|
23
|
+
# * Carnet
|
24
|
+
# * Synchrony
|
25
|
+
# * Routex
|
21
26
|
# * Elo
|
22
27
|
# * Alelo
|
23
28
|
# * Cabal
|
@@ -97,6 +102,11 @@ module ActiveMerchant #:nodoc:
|
|
97
102
|
# * +'dankort'+
|
98
103
|
# * +'maestro'+
|
99
104
|
# * +'forbrugsforeningen'+
|
105
|
+
# * +'sodexo'+
|
106
|
+
# * +'vr'+
|
107
|
+
# * +'carnet'+
|
108
|
+
# * +'synchrony'+
|
109
|
+
# * +'routex'+
|
100
110
|
# * +'elo'+
|
101
111
|
# * +'alelo'+
|
102
112
|
# * +'cabal'+
|
@@ -41,7 +41,7 @@ module ActiveMerchant #:nodoc:
|
|
41
41
|
def purchase(money, payment_object, options = {})
|
42
42
|
post = {}
|
43
43
|
add_creditcard(post, payment_object)
|
44
|
-
add_invoice(post, options)
|
44
|
+
add_invoice(post, money, options)
|
45
45
|
add_address(post, options)
|
46
46
|
add_customer_data(post, options)
|
47
47
|
commit('SALE', money, post)
|
@@ -50,7 +50,7 @@ module ActiveMerchant #:nodoc:
|
|
50
50
|
def refund(money, identification, options = {})
|
51
51
|
post = {}
|
52
52
|
post[:origtx] = identification
|
53
|
-
add_invoice(post, options)
|
53
|
+
add_invoice(post, money, options)
|
54
54
|
add_customer_data(post, options)
|
55
55
|
commit('REFUND', money, post)
|
56
56
|
end
|
@@ -69,7 +69,6 @@ module ActiveMerchant #:nodoc:
|
|
69
69
|
private
|
70
70
|
|
71
71
|
def commit(action, money, fields)
|
72
|
-
fields[:amount] = amount(money)
|
73
72
|
url = (test? ? test_url : live_url) + CGI.escape(@options[:merchant_gateway_name])
|
74
73
|
raw_response = ssl_post(url, post_data(action, fields))
|
75
74
|
parsed_response = parse(raw_response)
|
@@ -92,6 +91,7 @@ module ActiveMerchant #:nodoc:
|
|
92
91
|
|
93
92
|
def post_data(action, parameters = {})
|
94
93
|
post = {}
|
94
|
+
|
95
95
|
post[:command] = action
|
96
96
|
post[:merchant] = @options[:merchant]
|
97
97
|
post[:operator] = @options[:operator]
|
@@ -110,9 +110,19 @@ module ActiveMerchant #:nodoc:
|
|
110
110
|
post[:lname] = creditcard.last_name
|
111
111
|
end
|
112
112
|
|
113
|
-
def add_invoice(post, options)
|
113
|
+
def add_invoice(post, money, options)
|
114
114
|
post[:order_number] = options[:order_id] if options[:order_id].present?
|
115
|
-
|
115
|
+
|
116
|
+
if options[:item_codes].present?
|
117
|
+
codes_and_amounts = options[:item_codes].transform_keys { |key| key.to_s.delete('_') }
|
118
|
+
codes_and_amounts.each do |key, value|
|
119
|
+
post[key] = value if key.start_with?('itemcode')
|
120
|
+
post[key] = amount(value.to_i) if key.start_with?('amount')
|
121
|
+
end
|
122
|
+
else
|
123
|
+
post[:itemcode] = (options[:item_code] || @options[:default_item_code])
|
124
|
+
post[:amount] = amount(money.to_i)
|
125
|
+
end
|
116
126
|
end
|
117
127
|
|
118
128
|
def add_address(post, options)
|
@@ -87,6 +87,8 @@ module ActiveMerchant #:nodoc:
|
|
87
87
|
add_transaction_data(post, options)
|
88
88
|
add_3ds(post, options)
|
89
89
|
add_metadata(post, options)
|
90
|
+
add_processing_channel(post, options)
|
91
|
+
add_marketplace_data(post, options)
|
90
92
|
end
|
91
93
|
|
92
94
|
def add_invoice(post, money, options)
|
@@ -109,12 +111,17 @@ module ActiveMerchant #:nodoc:
|
|
109
111
|
|
110
112
|
def add_payment_method(post, payment_method, options)
|
111
113
|
post[:source] = {}
|
112
|
-
if payment_method.is_a?(NetworkTokenizationCreditCard)
|
114
|
+
if payment_method.is_a?(NetworkTokenizationCreditCard)
|
115
|
+
token_type = token_type_from(payment_method)
|
116
|
+
cryptogram = payment_method.payment_cryptogram
|
117
|
+
eci = payment_method.eci || options[:eci]
|
118
|
+
eci ||= '05' if token_type == 'vts'
|
119
|
+
|
113
120
|
post[:source][:type] = 'network_token'
|
114
121
|
post[:source][:token] = payment_method.number
|
115
|
-
post[:source][:token_type] =
|
116
|
-
post[:source][:cryptogram] =
|
117
|
-
post[:source][:eci] =
|
122
|
+
post[:source][:token_type] = token_type
|
123
|
+
post[:source][:cryptogram] = cryptogram if cryptogram
|
124
|
+
post[:source][:eci] = eci if eci
|
118
125
|
else
|
119
126
|
post[:source][:type] = 'card'
|
120
127
|
post[:source][:name] = payment_method.name
|
@@ -186,6 +193,17 @@ module ActiveMerchant #:nodoc:
|
|
186
193
|
end
|
187
194
|
end
|
188
195
|
|
196
|
+
def add_processing_channel(post, options)
|
197
|
+
post[:processing_channel_id] = options[:processing_channel_id] if options[:processing_channel_id]
|
198
|
+
end
|
199
|
+
|
200
|
+
def add_marketplace_data(post, options)
|
201
|
+
if options[:marketplace]
|
202
|
+
post[:marketplace] = {}
|
203
|
+
post[:marketplace][:sub_entity_id] = options[:marketplace][:sub_entity_id] if options[:marketplace][:sub_entity_id]
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
189
207
|
def commit(action, post, authorization = nil)
|
190
208
|
begin
|
191
209
|
raw_response = (action == :verify_payment ? ssl_get("#{base_url}/payments/#{post}", headers) : ssl_post(url(post, action, authorization), post.to_json, headers))
|
@@ -306,6 +324,17 @@ module ActiveMerchant #:nodoc:
|
|
306
324
|
STANDARD_ERROR_CODE_MAPPING[response['response_code']]
|
307
325
|
end
|
308
326
|
end
|
327
|
+
|
328
|
+
def token_type_from(payment_method)
|
329
|
+
case payment_method.source
|
330
|
+
when :network_token
|
331
|
+
payment_method.brand == 'visa' ? 'vts' : 'mdes'
|
332
|
+
when :google_pay, :android_pay
|
333
|
+
'googlepay'
|
334
|
+
when :apple_pay
|
335
|
+
'applepay'
|
336
|
+
end
|
337
|
+
end
|
309
338
|
end
|
310
339
|
end
|
311
340
|
end
|
@@ -500,6 +500,8 @@ module ActiveMerchant #:nodoc:
|
|
500
500
|
end
|
501
501
|
|
502
502
|
def add_line_item_data(xml, options)
|
503
|
+
return unless options[:line_items]
|
504
|
+
|
503
505
|
options[:line_items].each_with_index do |value, index|
|
504
506
|
xml.tag! 'item', { 'id' => index } do
|
505
507
|
xml.tag! 'unitPrice', localized_amount(value[:declared_value].to_i, options[:currency] || default_currency)
|
@@ -507,6 +509,8 @@ module ActiveMerchant #:nodoc:
|
|
507
509
|
xml.tag! 'productCode', value[:code] || 'shipping_only'
|
508
510
|
xml.tag! 'productName', value[:description]
|
509
511
|
xml.tag! 'productSKU', value[:sku]
|
512
|
+
xml.tag! 'taxAmount', value[:tax_amount] if value[:tax_amount]
|
513
|
+
xml.tag! 'nationalTax', value[:national_tax] if value[:national_tax]
|
510
514
|
end
|
511
515
|
end
|
512
516
|
end
|
@@ -522,10 +526,12 @@ module ActiveMerchant #:nodoc:
|
|
522
526
|
end
|
523
527
|
|
524
528
|
def add_merchant_descriptor(xml, options)
|
525
|
-
return unless options[:merchant_descriptor]
|
529
|
+
return unless options[:merchant_descriptor] || options[:user_po] || options[:taxable]
|
526
530
|
|
527
531
|
xml.tag! 'invoiceHeader' do
|
528
|
-
xml.tag! 'merchantDescriptor', options[:merchant_descriptor]
|
532
|
+
xml.tag! 'merchantDescriptor', options[:merchant_descriptor] if options[:merchant_descriptor]
|
533
|
+
xml.tag! 'userPO', options[:user_po] if options[:user_po]
|
534
|
+
xml.tag! 'taxable', options[:taxable] if options[:taxable]
|
529
535
|
end
|
530
536
|
end
|
531
537
|
|
@@ -628,11 +634,12 @@ module ActiveMerchant #:nodoc:
|
|
628
634
|
end
|
629
635
|
|
630
636
|
def add_other_tax(xml, options)
|
631
|
-
return unless options[:local_tax_amount] || options[:national_tax_amount]
|
637
|
+
return unless options[:local_tax_amount] || options[:national_tax_amount] || options[:national_tax_indicator]
|
632
638
|
|
633
639
|
xml.tag! 'otherTax' do
|
634
640
|
xml.tag! 'localTaxAmount', options[:local_tax_amount] if options[:local_tax_amount]
|
635
641
|
xml.tag! 'nationalTaxAmount', options[:national_tax_amount] if options[:national_tax_amount]
|
642
|
+
xml.tag! 'nationalTaxIndicator', options[:national_tax_indicator] if options[:national_tax_indicator]
|
636
643
|
end
|
637
644
|
end
|
638
645
|
|
@@ -887,6 +894,7 @@ module ActiveMerchant #:nodoc:
|
|
887
894
|
else
|
888
895
|
add_address(xml, payment_method_or_reference, options[:billing_address], options)
|
889
896
|
add_address(xml, payment_method_or_reference, options[:shipping_address], options, true)
|
897
|
+
add_line_item_data(xml, options)
|
890
898
|
add_purchase_data(xml, money, true, options)
|
891
899
|
add_installments(xml, options)
|
892
900
|
add_creditcard(xml, payment_method_or_reference)
|
@@ -26,6 +26,7 @@ module ActiveMerchant #:nodoc:
|
|
26
26
|
def authorize(money, payment, options = {})
|
27
27
|
post = {}
|
28
28
|
add_auth_purchase_params(post, money, payment, 'authorize', options)
|
29
|
+
post[:card][:verify] = true if options[:verify].to_s == 'true'
|
29
30
|
|
30
31
|
commit('authorize', post, options)
|
31
32
|
end
|
@@ -52,10 +53,7 @@ module ActiveMerchant #:nodoc:
|
|
52
53
|
end
|
53
54
|
|
54
55
|
def verify(credit_card, options = {})
|
55
|
-
|
56
|
-
r.process { authorize(100, credit_card, options) }
|
57
|
-
r.process(:ignore_result) { void(r.authorization, options) }
|
58
|
-
end
|
56
|
+
authorize(0, credit_card, options.merge(verify: 'true'))
|
59
57
|
end
|
60
58
|
|
61
59
|
def supports_scrubbing?
|
@@ -191,7 +189,7 @@ module ActiveMerchant #:nodoc:
|
|
191
189
|
def success_from(action, response)
|
192
190
|
return false unless response['status_code']
|
193
191
|
|
194
|
-
%w[100 200 400 600].include? response['status_code'].to_s
|
192
|
+
%w[100 200 400 600 700].include? response['status_code'].to_s
|
195
193
|
end
|
196
194
|
|
197
195
|
def message_from(action, response)
|
@@ -235,6 +233,7 @@ module ActiveMerchant #:nodoc:
|
|
235
233
|
'X-Date' => timestamp,
|
236
234
|
'X-Login' => @options[:login],
|
237
235
|
'X-Trans-Key' => @options[:trans_key],
|
236
|
+
'X-Version' => '2.1',
|
238
237
|
'Authorization' => signature(post, timestamp)
|
239
238
|
}
|
240
239
|
headers.merge('X-Idempotency-Key' => options[:idempotency_key]) if options[:idempotency_key]
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class DecidirPlusGateway < Gateway
|
4
|
+
self.test_url = 'https://developers.decidir.com/api/v2'
|
5
|
+
self.live_url = 'https://live.decidir.com/api/v2'
|
6
|
+
|
7
|
+
self.supported_countries = ['AR']
|
8
|
+
self.default_currency = 'ARS'
|
9
|
+
self.supported_cardtypes = %i[visa master american_express discover]
|
10
|
+
|
11
|
+
self.homepage_url = 'http://decidir.com.ar/home'
|
12
|
+
self.display_name = 'Decidir Plus'
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
requires!(options, :public_key, :private_key)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def purchase(money, payment, options = {})
|
20
|
+
post = {}
|
21
|
+
|
22
|
+
add_payment(post, payment, options)
|
23
|
+
add_purchase_data(post, money, payment, options)
|
24
|
+
|
25
|
+
commit(:post, 'payments', post)
|
26
|
+
end
|
27
|
+
|
28
|
+
def refund(money, authorization, options = {})
|
29
|
+
post = {}
|
30
|
+
post[:amount] = money
|
31
|
+
|
32
|
+
commit(:post, "payments/#{add_reference(authorization)}/refunds")
|
33
|
+
end
|
34
|
+
|
35
|
+
def store(payment, options = {})
|
36
|
+
post = {}
|
37
|
+
add_payment(post, payment, options)
|
38
|
+
|
39
|
+
commit(:post, 'tokens', post)
|
40
|
+
end
|
41
|
+
|
42
|
+
def supports_scrubbing?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def scrub(transcript)
|
47
|
+
transcript.
|
48
|
+
gsub(%r((Apikey: )\w+), '\1[FILTERED]').
|
49
|
+
gsub(%r(("card_number\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
|
50
|
+
gsub(%r(("security_code\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]')
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def add_reference(authorization)
|
56
|
+
return unless authorization
|
57
|
+
|
58
|
+
authorization.split('|')[0]
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_payment(post, payment, options = {})
|
62
|
+
if payment.is_a?(String)
|
63
|
+
token, bin = payment.split('|')
|
64
|
+
post[:token] = token
|
65
|
+
post[:bin] = bin
|
66
|
+
else
|
67
|
+
post[:card_number] = payment.number
|
68
|
+
post[:card_expiration_month] = payment.month.to_s.rjust(2, '0')
|
69
|
+
post[:card_expiration_year] = payment.year.to_s[-2..-1]
|
70
|
+
post[:security_code] = payment.verification_value.to_s
|
71
|
+
post[:card_holder_name] = payment.name
|
72
|
+
post[:card_holder_identification] = {}
|
73
|
+
post[:card_holder_identification][:type] = options[:dni]
|
74
|
+
post[:card_holder_identification][:number] = options[:card_holder_identification_number]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_purchase_data(post, money, payment, options = {})
|
79
|
+
post[:site_transaction_id] = options[:site_transaction_id] || SecureRandom.hex
|
80
|
+
post[:payment_method_id] = 1
|
81
|
+
post[:amount] = money
|
82
|
+
post[:currency] = options[:currency] || self.default_currency
|
83
|
+
post[:installments] = options[:installments] || 1
|
84
|
+
post[:payment_type] = options[:payment_type] || 'single'
|
85
|
+
add_sub_payments(post, options)
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_sub_payments(post, options)
|
89
|
+
# sub_payments field is required for purchase transactions, even if empty
|
90
|
+
post[:sub_payments] = []
|
91
|
+
|
92
|
+
return unless sub_payments = options[:sub_payments]
|
93
|
+
|
94
|
+
sub_payments.each do |sub_payment|
|
95
|
+
sub_payment_hash = {
|
96
|
+
site_id: sub_payment[:site_id],
|
97
|
+
installments: sub_payment[:installments],
|
98
|
+
amount: sub_payment[:amount]
|
99
|
+
}
|
100
|
+
post[:sub_payments] << sub_payment_hash
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse(body)
|
105
|
+
JSON.parse(body)
|
106
|
+
end
|
107
|
+
|
108
|
+
def commit(method, endpoint, parameters = {}, options = {})
|
109
|
+
begin
|
110
|
+
raw_response = ssl_request(method, url(endpoint), post_data(parameters), headers(endpoint))
|
111
|
+
response = parse(raw_response)
|
112
|
+
rescue ResponseError => e
|
113
|
+
raw_response = e.response.body
|
114
|
+
response = parse(raw_response)
|
115
|
+
end
|
116
|
+
|
117
|
+
Response.new(
|
118
|
+
success_from(response),
|
119
|
+
message_from(response),
|
120
|
+
response,
|
121
|
+
authorization: authorization_from(response),
|
122
|
+
avs_result: AVSResult.new(code: response['some_avs_response_key']),
|
123
|
+
cvv_result: CVVResult.new(response['some_cvv_response_key']),
|
124
|
+
test: test?,
|
125
|
+
error_code: error_code_from(response)
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
def headers(endpoint)
|
130
|
+
{
|
131
|
+
'Content-Type' => 'application/json',
|
132
|
+
'apikey' => endpoint == 'tokens' ? @options[:public_key] : @options[:private_key]
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
def url(action, options = {})
|
137
|
+
base_url = (test? ? test_url : live_url)
|
138
|
+
|
139
|
+
return "#{base_url}/#{action}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def success_from(response)
|
143
|
+
response.dig('status') == 'approved' || response.dig('status') == 'active'
|
144
|
+
end
|
145
|
+
|
146
|
+
def message_from(response)
|
147
|
+
response.dig('status') || error_message(response) || response.dig('message')
|
148
|
+
end
|
149
|
+
|
150
|
+
def authorization_from(response)
|
151
|
+
return nil unless response.dig('id') || response.dig('bin')
|
152
|
+
|
153
|
+
"#{response.dig('id')}|#{response.dig('bin')}"
|
154
|
+
end
|
155
|
+
|
156
|
+
def post_data(parameters = {})
|
157
|
+
parameters.to_json
|
158
|
+
end
|
159
|
+
|
160
|
+
def error_code_from(response)
|
161
|
+
response.dig('error_type') unless success_from(response)
|
162
|
+
end
|
163
|
+
|
164
|
+
def error_message(response)
|
165
|
+
return error_code_from(response) unless validation_errors = response.dig('validation_errors')
|
166
|
+
|
167
|
+
validation_errors = validation_errors[0]
|
168
|
+
|
169
|
+
"#{validation_errors.dig('code')}: #{validation_errors.dig('param')}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -214,6 +214,7 @@ module ActiveMerchant #:nodoc:
|
|
214
214
|
post[:metadata] = options[:metadata] if options[:metadata]
|
215
215
|
post[:metadata] = {} if post[:metadata].nil?
|
216
216
|
post[:metadata][:merchant_payment_code] = options[:order_id] if options[:order_id]
|
217
|
+
post[:processing_type] = options[:processing_type] if options[:processing_type]
|
217
218
|
end
|
218
219
|
|
219
220
|
def parse(body)
|
@@ -222,7 +223,8 @@ module ActiveMerchant #:nodoc:
|
|
222
223
|
|
223
224
|
def commit(action, parameters)
|
224
225
|
url = url_for((test? ? test_url : live_url), action, parameters)
|
225
|
-
|
226
|
+
|
227
|
+
response = parse(ssl_request(HTTP_METHOD[action], url, post_data(action, parameters), headers(parameters)))
|
226
228
|
|
227
229
|
success = success_from(action, response)
|
228
230
|
|
@@ -236,6 +238,19 @@ module ActiveMerchant #:nodoc:
|
|
236
238
|
)
|
237
239
|
end
|
238
240
|
|
241
|
+
def headers(params)
|
242
|
+
processing_type = params[:processing_type]
|
243
|
+
commit_headers = { 'x-ebanx-client-user-agent': "ActiveMerchant/#{ActiveMerchant::VERSION}" }
|
244
|
+
|
245
|
+
add_processing_type_to_commit_headers(commit_headers, processing_type) if processing_type == 'local'
|
246
|
+
|
247
|
+
commit_headers
|
248
|
+
end
|
249
|
+
|
250
|
+
def add_processing_type_to_commit_headers(commit_headers, processing_type)
|
251
|
+
commit_headers['x-ebanx-api-processing-type'] = processing_type
|
252
|
+
end
|
253
|
+
|
239
254
|
def success_from(action, response)
|
240
255
|
if %i[purchase capture refund].include?(action)
|
241
256
|
response.try(:[], 'payment').try(:[], 'status') == 'CO'
|
@@ -298,7 +298,7 @@ module ActiveMerchant #:nodoc:
|
|
298
298
|
xml.ssl_dynamic_dba options[:dba] if options.has_key?(:dba)
|
299
299
|
xml.ssl_merchant_initiated_unscheduled merchant_initiated_unscheduled(options) if merchant_initiated_unscheduled(options)
|
300
300
|
xml.ssl_add_token options[:add_recurring_token] if options.has_key?(:add_recurring_token)
|
301
|
-
xml.ssl_token options[:ssl_token] if options
|
301
|
+
xml.ssl_token options[:ssl_token] if options[:ssl_token]
|
302
302
|
xml.ssl_customer_code options[:customer] if options.has_key?(:customer)
|
303
303
|
xml.ssl_customer_number options[:customer_number] if options.has_key?(:customer_number)
|
304
304
|
xml.ssl_entry_mode entry_mode(options) if entry_mode(options)
|
@@ -393,6 +393,7 @@ module ActiveMerchant #:nodoc:
|
|
393
393
|
|
394
394
|
def commit(request)
|
395
395
|
request = "xmldata=#{request}".delete('&')
|
396
|
+
store_action = request.match?('CCGETTOKEN')
|
396
397
|
|
397
398
|
response = parse(ssl_post(test? ? self.test_url : self.live_url, request, headers))
|
398
399
|
response = hash_html_decode(response)
|
@@ -402,7 +403,7 @@ module ActiveMerchant #:nodoc:
|
|
402
403
|
response[:result_message] || response[:errorMessage],
|
403
404
|
response,
|
404
405
|
test: @options[:test] || test?,
|
405
|
-
authorization: authorization_from(response),
|
406
|
+
authorization: authorization_from(response, store_action),
|
406
407
|
error_code: response[:errorCode],
|
407
408
|
avs_result: { code: response[:avs_response] },
|
408
409
|
cvv_result: response[:cvv2_response],
|
@@ -428,7 +429,9 @@ module ActiveMerchant #:nodoc:
|
|
428
429
|
response.deep_transform_keys { |key| key.gsub('ssl_', '').to_sym }
|
429
430
|
end
|
430
431
|
|
431
|
-
def authorization_from(response)
|
432
|
+
def authorization_from(response, store_action)
|
433
|
+
return response[:token] if store_action
|
434
|
+
|
432
435
|
[response[:approval_code], response[:txn_id]].join(';')
|
433
436
|
end
|
434
437
|
|
@@ -82,6 +82,19 @@ module ActiveMerchant #:nodoc:
|
|
82
82
|
commit('CreditCardReturn', request, money)
|
83
83
|
end
|
84
84
|
|
85
|
+
def credit(money, payment, options = {})
|
86
|
+
request = build_soap_request do |xml|
|
87
|
+
xml.CreditCardCredit(xmlns: 'https://transaction.elementexpress.com') do
|
88
|
+
add_credentials(xml)
|
89
|
+
add_payment_method(xml, payment)
|
90
|
+
add_transaction(xml, money, options)
|
91
|
+
add_terminal(xml, options)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
commit('CreditCardCredit', request, money)
|
96
|
+
end
|
97
|
+
|
85
98
|
def void(authorization, options = {})
|
86
99
|
trans_id, trans_amount = split_authorization(authorization)
|
87
100
|
options.merge!({ trans_id: trans_id, trans_amount: trans_amount, reversal_type: 'Full' })
|
@@ -186,9 +199,10 @@ module ActiveMerchant #:nodoc:
|
|
186
199
|
xml.ReversalType options[:reversal_type] if options[:reversal_type]
|
187
200
|
xml.TransactionID options[:trans_id] if options[:trans_id]
|
188
201
|
xml.TransactionAmount amount(money.to_i) if money
|
189
|
-
xml.MarketCode
|
202
|
+
xml.MarketCode market_code(money, options) if options[:market_code] || money
|
190
203
|
xml.ReferenceNumber options[:order_id] || SecureRandom.hex(20)
|
191
|
-
|
204
|
+
xml.TicketNumber options[:ticket_number] if options[:ticket_number]
|
205
|
+
xml.MerchantSuppliedTransactionId options[:merchant_supplied_transaction_id] if options[:merchant_supplied_transaction_id]
|
192
206
|
xml.PaymentType options[:payment_type] if options[:payment_type]
|
193
207
|
xml.SubmissionType options[:submission_type] if options[:submission_type]
|
194
208
|
xml.DuplicateCheckDisableFlag options[:duplicate_check_disable_flag].to_s == 'true' ? 'True' : 'False' unless options[:duplicate_check_disable_flag].nil?
|
@@ -197,6 +211,10 @@ module ActiveMerchant #:nodoc:
|
|
197
211
|
end
|
198
212
|
end
|
199
213
|
|
214
|
+
def market_code(money, options)
|
215
|
+
options[:market_code] || 'Default'
|
216
|
+
end
|
217
|
+
|
200
218
|
def add_terminal(xml, options)
|
201
219
|
xml.terminal do
|
202
220
|
xml.TerminalID options[:terminal_id] || '01'
|