activemerchant 1.124.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 +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'
|