activemerchant 1.125.0 → 1.126.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 +75 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +12 -0
- data/lib/active_merchant/billing/gateway.rb +2 -1
- data/lib/active_merchant/billing/gateways/adyen.rb +7 -4
- data/lib/active_merchant/billing/gateways/airwallex.rb +341 -0
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +2 -1
- data/lib/active_merchant/billing/gateways/blue_pay.rb +1 -1
- data/lib/active_merchant/billing/gateways/blue_snap.rb +31 -21
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +6 -1
- data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +113 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +87 -15
- data/lib/active_merchant/billing/gateways/card_connect.rb +1 -1
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +1 -1
- data/lib/active_merchant/billing/gateways/credorax.rb +10 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +13 -33
- data/lib/active_merchant/billing/gateways/d_local.rb +49 -0
- data/lib/active_merchant/billing/gateways/decidir.rb +17 -1
- data/lib/active_merchant/billing/gateways/decidir_plus.rb +185 -14
- data/lib/active_merchant/billing/gateways/ebanx.rb +3 -2
- data/lib/active_merchant/billing/gateways/global_collect.rb +26 -16
- data/lib/active_merchant/billing/gateways/ipg.rb +1 -2
- data/lib/active_merchant/billing/gateways/litle.rb +93 -1
- data/lib/active_merchant/billing/gateways/moneris.rb +35 -8
- data/lib/active_merchant/billing/gateways/nmi.rb +12 -7
- data/lib/active_merchant/billing/gateways/orbital.rb +349 -327
- data/lib/active_merchant/billing/gateways/payflow.rb +62 -0
- data/lib/active_merchant/billing/gateways/paymentez.rb +26 -7
- data/lib/active_merchant/billing/gateways/paysafe.rb +15 -15
- data/lib/active_merchant/billing/gateways/payu_latam.rb +25 -15
- data/lib/active_merchant/billing/gateways/priority.rb +158 -136
- data/lib/active_merchant/billing/gateways/rapyd.rb +258 -0
- data/lib/active_merchant/billing/gateways/safe_charge.rb +1 -4
- data/lib/active_merchant/billing/gateways/simetrik.rb +362 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +4 -2
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +93 -48
- data/lib/active_merchant/billing/gateways/visanet_peru.rb +6 -2
- 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: 5bd1687aa128f1fce724fd39276bdb068552dc55e5dadeeab08a127781d54b31
|
4
|
+
data.tar.gz: 9519db6995b762487012de3fb0e47ef2f89587d26889fb6c2bbc0e1a74a88713
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af5c8f0f3d87e24ab864c880bde2be9374a60ebb47fdb57feafd0e80e790f585a18be65e331d07b2029c8679e1d35fb7f3baa482590da5bb4959828d5e7f5526
|
7
|
+
data.tar.gz: e2584e54260092929898ef7af600eecdb28d9641b7de50519eab20e1ad7929c67aada43ab93166af057e18f1f408fc9c9d45b36c010650d840b187661318f962
|
data/CHANGELOG
CHANGED
@@ -3,6 +3,79 @@
|
|
3
3
|
|
4
4
|
== HEAD
|
5
5
|
|
6
|
+
== Version 1.126.0 (April 15th, 2022)
|
7
|
+
* Moneris: Add 3DS MPI field support [esmitperez] #4373
|
8
|
+
* StripePI: Add ability to change payment_method_type to confirm_intent [aenand] #4300
|
9
|
+
* GlobalCollect: Improve support for Naranja and Cabal card types [dsmcclain] #4286
|
10
|
+
* Payflow: Add support for stored credentials [ajawadmirza] #4277
|
11
|
+
* Orbital: Don't void $0 auths for Verify [javierpedrozaing] #2487
|
12
|
+
* StripePI: Enable Apple Pay and Google Pay payment methods [gasb150] #4252
|
13
|
+
* PaySafe: Update `unstore` method and authorization for redact [ajawadmirza] #4294
|
14
|
+
* CyberSource: Add `national_tax_indicator` fields in authorize and purchase [ajawadmirza] #4299
|
15
|
+
* NMI: Update gateway credentials to accept security_key [javierpedrozaing] #4302
|
16
|
+
* PaySafe: Fix commit for `unstore` method [ajawadmirza] #4303
|
17
|
+
* Ebanx: Add support for `order_number` field [ali-hassan] #4304
|
18
|
+
* BlueSnap: Add support for `idempotency_key` field [drkjc] #4305
|
19
|
+
* Paymentez: Update `capture` method to verify by otp for pending transactions [ajawadmirza] #4267
|
20
|
+
* BlueSnap: Update refund request and endpoint along with merchant transaction support [ajawadmirza] #4307
|
21
|
+
* DecidirPlus: Added `authorize`, `capture`, `void`, and `verify` methods [ajawadmirza] #4284
|
22
|
+
* Paymentez: Fix `authorize` to call `purchase` for otp flow [ajawadmirza] #4310
|
23
|
+
* Orbital: Indicate support for network tokenization [dsmcclain] #4309
|
24
|
+
* IPG: remove `uruguay` from supported countries [ajawadmirza] #4311
|
25
|
+
* Decidir: Add sub_payments sub-fields to gateway [meagabeth] #4315
|
26
|
+
* Priority: Add additional fields to purchase and capture requests [dsmcclain] #4301
|
27
|
+
* DecidirPlus: Added `unstore` method [ajawadmirza] #4317
|
28
|
+
* Decidir & Decidir Plus: Revise handling of `sub_payment` sub-fields [meagabeth] #4318
|
29
|
+
* DecidirPlus: Update `unstore` implementation to get token from params [ajawadmirza] #4320
|
30
|
+
* CyberSource: Add option for zero amount verify [gasb150] #4313
|
31
|
+
* PayU Latam: Refactor `message_from` method, fix failing remote tests [rachelkirk] #4326
|
32
|
+
* Adyen: Add currencies with three decimals places [gasb150] #4322
|
33
|
+
* GlobalCollect: Stregthen success criteria for void action [peteroas] #4324
|
34
|
+
* Priority Payment Systems - Clean up/refactor gateway file and tests [ali-hassan] #4327
|
35
|
+
* SafeCharge: change `verify` to send 0 amount [dsmcclain] #4332
|
36
|
+
* DLocal: add support for `force_type` field [dsmcclain] #4336
|
37
|
+
* Barclaycard SmartPay: Support more nonstandard currencies [jherreraa] #4335
|
38
|
+
* DecidirPlus: `name_override` option on `store` [naashton] #4338
|
39
|
+
* Priority: Update `add_purchases_data` to return if `options[:purchases]` is empty [drkjc] #4349
|
40
|
+
* Stripe PI: update `shipping` field to `shipping_address` [ajawadmirza] #4347
|
41
|
+
* DecidirPlus: Handle `payment_method_id` by `card_brand` [naashton] #4350
|
42
|
+
* DecidirPlus: `debit` and `payment_method_id` fields [naashton] #4351
|
43
|
+
* Adyen: Include Application ID in adyen authorize and purchase transactions [peteroas] #4343
|
44
|
+
* Priority: Add support for `replay_id` field [drkjc] #4352
|
45
|
+
* Stripe PI: standardize `shipping_address` fields [dsmcclain] #4355
|
46
|
+
* Airwallex: support gateway [therufs] #4342
|
47
|
+
* Litle: Translate google_pay as android_pay [javierpedrozaing] #4331
|
48
|
+
* Braintree: Add ACH support for store [cristian] #4285
|
49
|
+
* Simetrik: Add support for Simetrik gateway [simetrik-frank] #4339
|
50
|
+
* EBANX: Change amount for Mexico and Chile [flaaviaa] #4337
|
51
|
+
* DecidirPlus: Add `establishment_name`, `aggregate_data`, `sub_payments`, `card_holder_identification_type`, `card_holder_identification_number`, `card_door_number`, and `card_holder_birthday` fields [ajawadmirza] #4361
|
52
|
+
* DecidirPlus: Update `error_code_from` to get error reason id [ajawadmirza] #4364
|
53
|
+
* Dlocal: Add three_ds mpi support [cristian] #4345
|
54
|
+
* Stripe PI: Add `request_three_d_secure` field for `create_setup_intent` [aenand] #4365
|
55
|
+
* Adyen: Add `verify_amount` field for verify [ajawadmirza] #4369
|
56
|
+
* Stripe PI: Pass options for tokenizing Apple/Google Pay [gasb150] #4368
|
57
|
+
* Dlocal: Format 3DS mpi enrollment data correctly [cristian] #4371
|
58
|
+
* Airwallex: QA fixes for option handling [therufs] #4367
|
59
|
+
* CardConnect: Fixed duplicate(concat) Address sent - card_connect is concat. address1 and 2 causing a AVS error [ahmirza] #4362
|
60
|
+
* CyberSource: Remove Pinless Debit Transaction Functionality [peteroas] #4370
|
61
|
+
* Litle: Add support for Level 2 and 3 enhanced data [curiousepic] #4360
|
62
|
+
* Rapyd: Add gateway support [meagabeth] #4372
|
63
|
+
* CyberSource: Update and fix test coverage [peteroas] #4374
|
64
|
+
* Airwallex: QA fixes for address and create_setup_intent handling [therufs] #4377
|
65
|
+
* Airwallex: add `descriptor` field and update logic for sending `request_id` and `merchant_order_id` [dsmcclain] #4379
|
66
|
+
* Visanet Peru: use timestamp instead of random for purchaseNumber [therufs] #4093
|
67
|
+
* Orbital: add `verify_amount` field [ajawadmirza] #4376
|
68
|
+
* Credorax: add `recipient_street_address`, `recipient_city`, `recipient_province_code`, and `recipient_country_code` fields [ajawadmirza] #4384
|
69
|
+
* Airwallex: add support for stored credentials [drkjc] #4382
|
70
|
+
* Rapyd: Add metadata and ewallet_id options [naashton] #4387
|
71
|
+
* Priority: Add additional fields to request and refactor gateway integration [dsmcclain] #4383
|
72
|
+
* Rapyd: Update `type` option to `pm_type` [naashton] #4391
|
73
|
+
* Conekta: Fix remote test [javierpedrozaing] #4386
|
74
|
+
* NMI: Update post URL [jherreraa] #4380
|
75
|
+
* Multiple Gateways: Resolve when/case bug [naashton] #4399
|
76
|
+
* Airwallex: Add 3DS MPI support [drkjc] #4395
|
77
|
+
* Add Cartes Bancaires card bin ranges [leahriffell] #4398
|
78
|
+
|
6
79
|
== Version 1.125.0 (January 20, 2022)
|
7
80
|
* Wompi: support gateway [therufs] #4173
|
8
81
|
* Stripe Payment Intents: Add setup_purchase [aenand] #4178
|
@@ -86,6 +159,8 @@
|
|
86
159
|
* Update inline documentation with all supported cardtypes [ali-hassan] #4283
|
87
160
|
* PayWay: Update endpoints, response code [jessiagee] #4281
|
88
161
|
* CyberSource: Add `line_items` for purchase [ajawadmirza] #4282
|
162
|
+
* Payflow Pro: Add `stored_credential` fields [ajawadmirza] #4277
|
163
|
+
* Decidir Plus: Add `fraud_detection` fields [naashton] #4289
|
89
164
|
|
90
165
|
== Version 1.124.0 (October 28th, 2021)
|
91
166
|
* Worldpay: Add Support for Submerchant Data on Worldpay [almalee24] #4147
|
@@ -34,6 +34,7 @@ module ActiveMerchant #:nodoc:
|
|
34
34
|
CARNET_BINS.any? { |bin| num.slice(0, bin.size) == bin }
|
35
35
|
)
|
36
36
|
},
|
37
|
+
'cartes_bancaires' => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), CARTES_BANCAIRES_RANGES) },
|
37
38
|
'olimpica' => ->(num) { num =~ /^636853\d{10}$/ },
|
38
39
|
'creditel' => ->(num) { num =~ /^601933\d{10}$/ },
|
39
40
|
'confiable' => ->(num) { num =~ /^560718\d{10}$/ },
|
@@ -73,6 +74,17 @@ module ActiveMerchant #:nodoc:
|
|
73
74
|
]
|
74
75
|
)
|
75
76
|
|
77
|
+
CARTES_BANCAIRES_RANGES = [
|
78
|
+
(507589..507590),
|
79
|
+
(507593..507595),
|
80
|
+
[507597],
|
81
|
+
[560408],
|
82
|
+
[581752],
|
83
|
+
(585402..585405),
|
84
|
+
(585501..585505),
|
85
|
+
(585577..585582)
|
86
|
+
]
|
87
|
+
|
76
88
|
# https://www.mastercard.us/content/dam/mccom/global/documents/mastercard-rules.pdf, page 73
|
77
89
|
MASTERCARD_RANGES = [
|
78
90
|
(222100..272099),
|
@@ -95,7 +95,8 @@ module ActiveMerchant #:nodoc:
|
|
95
95
|
pickup_card: 'pick_up_card',
|
96
96
|
config_error: 'config_error',
|
97
97
|
test_mode_live_card: 'test_mode_live_card',
|
98
|
-
unsupported_feature: 'unsupported_feature'
|
98
|
+
unsupported_feature: 'unsupported_feature',
|
99
|
+
invalid_amount: 'invalid_amount'
|
99
100
|
}
|
100
101
|
|
101
102
|
cattr_reader :implementations
|
@@ -9,6 +9,7 @@ module ActiveMerchant #:nodoc:
|
|
9
9
|
self.supported_countries = %w(AT AU BE BG BR CH CY CZ DE DK EE ES FI FR GB GI GR HK HU IE IS IT LI LT LU LV MC MT MX NL NO PL PT RO SE SG SK SI US)
|
10
10
|
self.default_currency = 'USD'
|
11
11
|
self.currencies_without_fractions = %w(CVE DJF GNF IDR JPY KMF KRW PYG RWF UGX VND VUV XAF XOF XPF)
|
12
|
+
self.currencies_with_three_decimal_places = %w(BHD IQD JOD KWD LYD OMR TND)
|
12
13
|
self.supported_cardtypes = %i[visa master american_express diners_club jcb dankort maestro discover elo naranja cabal unionpay]
|
13
14
|
|
14
15
|
self.money_format = :cents
|
@@ -143,8 +144,9 @@ module ActiveMerchant #:nodoc:
|
|
143
144
|
end
|
144
145
|
|
145
146
|
def verify(credit_card, options = {})
|
147
|
+
amount = options[:verify_amount]&.to_i || 0
|
146
148
|
MultiResponse.run(:use_first_response) do |r|
|
147
|
-
r.process { authorize(
|
149
|
+
r.process { authorize(amount, credit_card, options) }
|
148
150
|
options[:idempotency_key] = nil
|
149
151
|
r.process(:ignore_result) { void(r.authorization, options) }
|
150
152
|
end
|
@@ -461,12 +463,13 @@ module ActiveMerchant #:nodoc:
|
|
461
463
|
end
|
462
464
|
|
463
465
|
def add_external_platform(post, options)
|
466
|
+
options.update(externalPlatform: application_id) if application_id
|
467
|
+
|
464
468
|
return unless options[:externalPlatform]
|
465
469
|
|
466
470
|
post[:applicationInfo][:externalPlatform] = {
|
467
471
|
name: options[:externalPlatform][:name],
|
468
|
-
version: options[:externalPlatform][:version]
|
469
|
-
integrator: options[:externalPlatform][:integrator]
|
472
|
+
version: options[:externalPlatform][:version]
|
470
473
|
}
|
471
474
|
end
|
472
475
|
|
@@ -669,7 +672,7 @@ module ActiveMerchant #:nodoc:
|
|
669
672
|
end
|
670
673
|
|
671
674
|
def error_code_from(response)
|
672
|
-
STANDARD_ERROR_CODE_MAPPING[response['errorCode']]
|
675
|
+
STANDARD_ERROR_CODE_MAPPING[response['errorCode']] || response['errorCode']
|
673
676
|
end
|
674
677
|
|
675
678
|
def network_transaction_id_from(response)
|
@@ -0,0 +1,341 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class AirwallexGateway < Gateway
|
4
|
+
self.test_url = 'https://api-demo.airwallex.com/api/v1'
|
5
|
+
self.live_url = 'https://pci-api.airwallex.com/api/v1'
|
6
|
+
|
7
|
+
# per https://www.airwallex.com/docs/online-payments__overview, cards are accepted in all EU countries
|
8
|
+
self.supported_countries = %w[AT AU BE BG CY CZ DE DK EE GR ES FI FR GB HK HR HU IE IT LT LU LV MT NL PL PT RO SE SG SI SK]
|
9
|
+
self.default_currency = 'AUD'
|
10
|
+
self.supported_cardtypes = %i[visa master]
|
11
|
+
|
12
|
+
self.homepage_url = 'https://airwallex.com/'
|
13
|
+
self.display_name = 'Airwallex'
|
14
|
+
|
15
|
+
ENDPOINTS = {
|
16
|
+
login: '/authentication/login',
|
17
|
+
setup: '/pa/payment_intents/create',
|
18
|
+
sale: '/pa/payment_intents/%{id}/confirm',
|
19
|
+
capture: '/pa/payment_intents/%{id}/capture',
|
20
|
+
refund: '/pa/refunds/create',
|
21
|
+
void: '/pa/payment_intents/%{id}/cancel'
|
22
|
+
}
|
23
|
+
|
24
|
+
def initialize(options = {})
|
25
|
+
requires!(options, :client_id, :client_api_key)
|
26
|
+
@client_id = options[:client_id]
|
27
|
+
@client_api_key = options[:client_api_key]
|
28
|
+
super
|
29
|
+
@access_token = setup_access_token
|
30
|
+
end
|
31
|
+
|
32
|
+
def purchase(money, card, options = {})
|
33
|
+
requires!(options, :return_url)
|
34
|
+
|
35
|
+
payment_intent_id = create_payment_intent(money, options)
|
36
|
+
post = {
|
37
|
+
'request_id' => request_id(options),
|
38
|
+
'merchant_order_id' => merchant_order_id(options),
|
39
|
+
'return_url' => options[:return_url]
|
40
|
+
}
|
41
|
+
add_card(post, card, options)
|
42
|
+
add_descriptor(post, options)
|
43
|
+
add_stored_credential(post, options)
|
44
|
+
post['payment_method_options'] = { 'card' => { 'auto_capture' => false } } if authorization_only?(options)
|
45
|
+
|
46
|
+
add_three_ds(post, options)
|
47
|
+
commit(:sale, post, payment_intent_id)
|
48
|
+
end
|
49
|
+
|
50
|
+
def authorize(money, payment, options = {})
|
51
|
+
# authorize is just a purchase w/o an auto capture
|
52
|
+
purchase(money, payment, options.merge({ auto_capture: false }))
|
53
|
+
end
|
54
|
+
|
55
|
+
def capture(money, authorization, options = {})
|
56
|
+
raise ArgumentError, 'An authorization value must be provided.' if authorization.blank?
|
57
|
+
|
58
|
+
post = {
|
59
|
+
'request_id' => request_id(options),
|
60
|
+
'merchant_order_id' => merchant_order_id(options),
|
61
|
+
'amount' => amount(money)
|
62
|
+
}
|
63
|
+
add_descriptor(post, options)
|
64
|
+
|
65
|
+
commit(:capture, post, authorization)
|
66
|
+
end
|
67
|
+
|
68
|
+
def refund(money, authorization, options = {})
|
69
|
+
raise ArgumentError, 'An authorization value must be provided.' if authorization.blank?
|
70
|
+
|
71
|
+
post = {}
|
72
|
+
post[:amount] = amount(money)
|
73
|
+
post[:payment_intent_id] = authorization
|
74
|
+
post[:request_id] = request_id(options)
|
75
|
+
post[:merchant_order_id] = merchant_order_id(options)
|
76
|
+
|
77
|
+
commit(:refund, post)
|
78
|
+
end
|
79
|
+
|
80
|
+
def void(authorization, options = {})
|
81
|
+
raise ArgumentError, 'An authorization value must be provided.' if authorization.blank?
|
82
|
+
|
83
|
+
post = {}
|
84
|
+
post[:request_id] = request_id(options)
|
85
|
+
post[:merchant_order_id] = merchant_order_id(options)
|
86
|
+
add_descriptor(post, options)
|
87
|
+
|
88
|
+
commit(:void, post, authorization)
|
89
|
+
end
|
90
|
+
|
91
|
+
def verify(credit_card, options = {})
|
92
|
+
MultiResponse.run(:use_first_response) do |r|
|
93
|
+
r.process { authorize(100, credit_card, options) }
|
94
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def supports_scrubbing?
|
99
|
+
true
|
100
|
+
end
|
101
|
+
|
102
|
+
def scrub(transcript)
|
103
|
+
transcript.
|
104
|
+
gsub(/(\\\"number\\\":\\\")\d+/, '\1[REDACTED]').
|
105
|
+
gsub(/(\\\"cvc\\\":\\\")\d+/, '\1[REDACTED]')
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def request_id(options)
|
111
|
+
options[:request_id] || generate_timestamp
|
112
|
+
end
|
113
|
+
|
114
|
+
def merchant_order_id(options)
|
115
|
+
options[:merchant_order_id] || options[:order_id] || generate_timestamp
|
116
|
+
end
|
117
|
+
|
118
|
+
def generate_timestamp
|
119
|
+
(Time.now.to_f.round(2) * 100).to_i.to_s
|
120
|
+
end
|
121
|
+
|
122
|
+
def setup_access_token
|
123
|
+
token_headers = {
|
124
|
+
'Content-Type' => 'application/json',
|
125
|
+
'x-client-id' => @client_id,
|
126
|
+
'x-api-key' => @client_api_key
|
127
|
+
}
|
128
|
+
response = ssl_post(build_request_url(:login), nil, token_headers)
|
129
|
+
JSON.parse(response)['token']
|
130
|
+
end
|
131
|
+
|
132
|
+
def build_request_url(action, id = nil)
|
133
|
+
base_url = (test? ? test_url : live_url)
|
134
|
+
base_url + ENDPOINTS[action].to_s % { id: id }
|
135
|
+
end
|
136
|
+
|
137
|
+
def create_payment_intent(money, options = {})
|
138
|
+
post = {}
|
139
|
+
add_invoice(post, money, options)
|
140
|
+
add_order(post, options)
|
141
|
+
post[:request_id] = "#{request_id(options)}_setup"
|
142
|
+
post[:merchant_order_id] = "#{merchant_order_id(options)}_setup"
|
143
|
+
add_descriptor(post, options)
|
144
|
+
|
145
|
+
response = commit(:setup, post)
|
146
|
+
raise ArgumentError.new(response.message) unless response.success?
|
147
|
+
|
148
|
+
response.params['id']
|
149
|
+
end
|
150
|
+
|
151
|
+
def add_billing(post, card, options = {})
|
152
|
+
return unless has_name_info?(card)
|
153
|
+
|
154
|
+
billing = post['payment_method']['card']['billing'] || {}
|
155
|
+
billing['email'] = options[:email] if options[:email]
|
156
|
+
billing['phone'] = options[:phone] if options[:phone]
|
157
|
+
billing['first_name'] = card.first_name
|
158
|
+
billing['last_name'] = card.last_name
|
159
|
+
billing_address = options[:billing_address]
|
160
|
+
billing['address'] = build_address(billing_address) if has_required_address_info?(billing_address)
|
161
|
+
|
162
|
+
post['payment_method']['card']['billing'] = billing
|
163
|
+
end
|
164
|
+
|
165
|
+
def has_name_info?(card)
|
166
|
+
# These fields are required if billing data is sent.
|
167
|
+
card.first_name && card.last_name
|
168
|
+
end
|
169
|
+
|
170
|
+
def has_required_address_info?(address)
|
171
|
+
# These fields are required if address data is sent.
|
172
|
+
return unless address
|
173
|
+
|
174
|
+
address[:address1] && address[:country]
|
175
|
+
end
|
176
|
+
|
177
|
+
def build_address(address)
|
178
|
+
return unless address
|
179
|
+
|
180
|
+
address_data = {} # names r hard
|
181
|
+
address_data[:country_code] = address[:country]
|
182
|
+
address_data[:street] = address[:address1]
|
183
|
+
address_data[:city] = address[:city] if address[:city] # required per doc, not in practice
|
184
|
+
address_data[:postcode] = address[:zip] if address[:zip]
|
185
|
+
address_data[:state] = address[:state] if address[:state]
|
186
|
+
address_data
|
187
|
+
end
|
188
|
+
|
189
|
+
def add_invoice(post, money, options)
|
190
|
+
post[:amount] = amount(money)
|
191
|
+
post[:currency] = (options[:currency] || currency(money))
|
192
|
+
end
|
193
|
+
|
194
|
+
def add_card(post, card, options = {})
|
195
|
+
post['payment_method'] = {
|
196
|
+
'type' => 'card',
|
197
|
+
'card' => {
|
198
|
+
'expiry_month' => format(card.month, :two_digits),
|
199
|
+
'expiry_year' => card.year.to_s,
|
200
|
+
'number' => card.number.to_s,
|
201
|
+
'name' => card.name,
|
202
|
+
'cvc' => card.verification_value
|
203
|
+
}
|
204
|
+
}
|
205
|
+
add_billing(post, card, options)
|
206
|
+
end
|
207
|
+
|
208
|
+
def add_order(post, options)
|
209
|
+
return unless shipping_address = options[:shipping_address]
|
210
|
+
|
211
|
+
physical_address = build_shipping_address(shipping_address)
|
212
|
+
first_name, last_name = split_names(shipping_address[:name])
|
213
|
+
shipping = {}
|
214
|
+
shipping[:first_name] = first_name if first_name
|
215
|
+
shipping[:last_name] = last_name if last_name
|
216
|
+
shipping[:phone_number] = shipping_address[:phone_number] if shipping_address[:phone_number]
|
217
|
+
shipping[:address] = physical_address
|
218
|
+
post[:order] = { shipping: shipping }
|
219
|
+
end
|
220
|
+
|
221
|
+
def build_shipping_address(shipping_address)
|
222
|
+
address = {}
|
223
|
+
address[:city] = shipping_address[:city]
|
224
|
+
address[:country_code] = shipping_address[:country]
|
225
|
+
address[:postcode] = shipping_address[:zip]
|
226
|
+
address[:state] = shipping_address[:state]
|
227
|
+
address[:street] = shipping_address[:address1]
|
228
|
+
address
|
229
|
+
end
|
230
|
+
|
231
|
+
def add_stored_credential(post, options)
|
232
|
+
return unless stored_credential = options[:stored_credential]
|
233
|
+
|
234
|
+
external_recurring_data = post[:external_recurring_data] = {}
|
235
|
+
|
236
|
+
case stored_credential.dig(:reason_type)
|
237
|
+
when 'recurring', 'installment'
|
238
|
+
external_recurring_data[:merchant_trigger_reason] = 'scheduled'
|
239
|
+
when 'unscheduled'
|
240
|
+
external_recurring_data[:merchant_trigger_reason] = 'unscheduled'
|
241
|
+
end
|
242
|
+
|
243
|
+
external_recurring_data[:original_transaction_id] = stored_credential.dig(:network_transaction_id)
|
244
|
+
external_recurring_data[:triggered_by] = stored_credential.dig(:initiator) == 'cardholder' ? 'customer' : 'merchant'
|
245
|
+
end
|
246
|
+
|
247
|
+
def add_three_ds(post, options)
|
248
|
+
return unless three_d_secure = options[:three_d_secure]
|
249
|
+
|
250
|
+
pm_options = post.dig('payment_method_options', 'card')
|
251
|
+
|
252
|
+
external_three_ds = {
|
253
|
+
'version': format_three_ds_version(three_d_secure),
|
254
|
+
'eci': three_d_secure[:eci]
|
255
|
+
}.merge(three_ds_version_specific_fields(three_d_secure))
|
256
|
+
|
257
|
+
pm_options ? pm_options.merge!('external_three_ds': external_three_ds) : post['payment_method_options'] = { 'card': { 'external_three_ds': external_three_ds } }
|
258
|
+
end
|
259
|
+
|
260
|
+
def format_three_ds_version(three_d_secure)
|
261
|
+
version = three_d_secure[:version].split('.')
|
262
|
+
|
263
|
+
version.push('0') until version.length == 3
|
264
|
+
version.join('.')
|
265
|
+
end
|
266
|
+
|
267
|
+
def three_ds_version_specific_fields(three_d_secure)
|
268
|
+
if three_d_secure[:version].to_f >= 2
|
269
|
+
{
|
270
|
+
'authentication_value': three_d_secure[:cavv],
|
271
|
+
'ds_transaction_id': three_d_secure[:ds_transaction_id],
|
272
|
+
'three_ds_server_transaction_id': three_d_secure[:three_ds_server_trans_id]
|
273
|
+
}
|
274
|
+
else
|
275
|
+
{
|
276
|
+
'cavv': three_d_secure[:cavv],
|
277
|
+
'xid': three_d_secure[:xid]
|
278
|
+
}
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def authorization_only?(options = {})
|
283
|
+
options.include?(:auto_capture) && options[:auto_capture] == false
|
284
|
+
end
|
285
|
+
|
286
|
+
def add_descriptor(post, options)
|
287
|
+
post[:descriptor] = options[:description] if options[:description]
|
288
|
+
end
|
289
|
+
|
290
|
+
def parse(body)
|
291
|
+
JSON.parse(body)
|
292
|
+
end
|
293
|
+
|
294
|
+
def commit(action, post, id = nil)
|
295
|
+
url = build_request_url(action, id)
|
296
|
+
post_headers = { 'Authorization' => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
297
|
+
response = parse(ssl_post(url, post_data(post), post_headers))
|
298
|
+
|
299
|
+
Response.new(
|
300
|
+
success_from(response),
|
301
|
+
message_from(response),
|
302
|
+
response,
|
303
|
+
authorization: authorization_from(response),
|
304
|
+
avs_result: AVSResult.new(code: response.dig('latest_payment_attempt', 'authentication_data', 'avs_result')),
|
305
|
+
cvv_result: CVVResult.new(response.dig('latest_payment_attempt', 'authentication_data', 'cvc_code')),
|
306
|
+
test: test?,
|
307
|
+
error_code: error_code_from(response)
|
308
|
+
)
|
309
|
+
end
|
310
|
+
|
311
|
+
def handle_response(response)
|
312
|
+
case response.code.to_i
|
313
|
+
when 200...300, 400, 404
|
314
|
+
response.body
|
315
|
+
else
|
316
|
+
raise ResponseError.new(response)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def post_data(post)
|
321
|
+
post.to_json
|
322
|
+
end
|
323
|
+
|
324
|
+
def success_from(response)
|
325
|
+
%w(REQUIRES_PAYMENT_METHOD SUCCEEDED RECEIVED REQUIRES_CAPTURE CANCELLED).include?(response['status'])
|
326
|
+
end
|
327
|
+
|
328
|
+
def message_from(response)
|
329
|
+
response.dig('latest_payment_attempt', 'status') || response['status'] || response['message']
|
330
|
+
end
|
331
|
+
|
332
|
+
def authorization_from(response)
|
333
|
+
response.dig('latest_payment_attempt', 'payment_intent_id')
|
334
|
+
end
|
335
|
+
|
336
|
+
def error_code_from(response)
|
337
|
+
response['provider_original_response_code'] || response['code'] unless success_from(response)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
@@ -6,9 +6,10 @@ module ActiveMerchant #:nodoc:
|
|
6
6
|
|
7
7
|
self.supported_countries = %w[AL AD AM AT AZ BY BE BA BG HR CY CZ DK EE FI FR DE GR HU IS IE IT KZ LV LI LT LU MK MT MD MC ME NL NO PL PT RO RU SM RS SK SI ES SE CH TR UA GB VA]
|
8
8
|
self.default_currency = 'EUR'
|
9
|
-
self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
|
9
|
+
self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND IQD JOD LYD)
|
10
10
|
self.money_format = :cents
|
11
11
|
self.supported_cardtypes = %i[visa master american_express discover diners_club jcb dankort maestro]
|
12
|
+
self.currencies_without_fractions = %w(CVE DJF GNF IDR JPY KMF KRW PYG RWF UGX VND VUV XAF XOF XPF)
|
12
13
|
|
13
14
|
self.homepage_url = 'https://www.barclaycardsmartpay.com/'
|
14
15
|
self.display_name = 'Barclaycard Smartpay'
|