activemerchant 1.102.0 → 1.103.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 676020bb24cc6d3a8b17a3d2ed035398803a436371c3c6a368ab3b49104d618e
4
- data.tar.gz: 5a46ff06616a3b914c599d7da7455f0a4dc1b7579907a03a2c51463d6c81a8ef
3
+ metadata.gz: a51e307707d9ffa9cd0d32779623b7095ea9af27f16078de9736be65fc8c0090
4
+ data.tar.gz: 27b16b69f6bb974795ddc1fae4d924257bee5c0620d0ab009b771b107d59be24
5
5
  SHA512:
6
- metadata.gz: b06c1bd98e25faed372c68877041f127a64b21021f88ec102dd0910d976eeaba2f19a4414a5b9d122fb5a92f64489d34e961652ad1a7aac6f85e802ada89d1cf
7
- data.tar.gz: 7cb0c86d44cbc7d23ea441aba7dc90ec58d7d5be2d972dd63c0b3545c4372c752d7fc068a173f0d26532f4cede6a97dcecae8fd86c40f17551c6017a9c07db1c
6
+ metadata.gz: 6d0e03c0a615dabf2ef0299baaac647eabe906f08bfbb3343e545d3a7ee1390678a963a4a1433b24cb478264b7ad260a30c947d827e91e835f6892ca31644399
7
+ data.tar.gz: db9a355a166614c1ebe4b018ba1a5634448bd5be14aa34e9db55837d529b1aad4f10994cf476793e38619fb7d8c7785ab014b5dac4d2a33bcea3720da8a98689
data/CHANGELOG CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  == HEAD
4
4
 
5
+ == Version 1.103.0 (Dec 2, 2019)
6
+ * Quickbooks: Mark transactions that returned `AuthorizationFailed` as failures [britth] #3447
7
+ * Credorax: Add referral CFT transactions [leila-alderman] #3432
8
+ * DLocal: Updates for version 2.1 [molbrown] #3449
9
+ * CyberSource: Send MDD on capture [leila-alderman] #3453
10
+ * Ixopay: Include extra_data gateway specific field [therufs] #3450
11
+ * CyberSource: Fix XML error on capture [leila-alderman] #3454
12
+ * Adyen: Add gateway specific field for splits [leila-alderman] #3448
13
+ * Adyen: Add `unstore` and `storeToken` actions with '/Recurring' endpoint [deedeelavinder][davidsantoso] #3438
14
+ * Barclaycard Smartpay: Add functionality to set 3DS exemptions via API [britth] #3457
15
+ * Use null@cybersource.com when option[:email] is an empty string [pi3r] #3462
16
+
5
17
  == Version 1.102.0 (Nov 14, 2019)
6
18
  * Quickbooks: Make token refresh optional with allow_refresh flag [britth] #3419
7
19
  * Paymentez: Update supported countries [curiousepic] #3425
@@ -4,10 +4,10 @@ module ActiveMerchant #:nodoc:
4
4
 
5
5
  # we recommend setting up merchant-specific endpoints.
6
6
  # https://docs.adyen.com/developers/api-manual#apiendpoints
7
- self.test_url = 'https://pal-test.adyen.com/pal/servlet/Payment/'
8
- self.live_url = 'https://pal-live.adyen.com/pal/servlet/Payment/'
7
+ self.test_url = 'https://pal-test.adyen.com/pal/servlet/'
8
+ self.live_url = 'https://pal-live.adyen.com/pal/servlet/'
9
9
 
10
- self.supported_countries = ['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
+ 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)
11
11
  self.default_currency = 'USD'
12
12
  self.currencies_without_fractions = %w(CVE DJF GNF IDR JPY KMF KRW PYG RWF UGX VND VUV XAF XOF XPF)
13
13
  self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb, :dankort, :maestro, :discover, :elo, :naranja, :cabal]
@@ -17,7 +17,8 @@ module ActiveMerchant #:nodoc:
17
17
  self.homepage_url = 'https://www.adyen.com/'
18
18
  self.display_name = 'Adyen'
19
19
 
20
- API_VERSION = 'v40'
20
+ PAYMENT_API_VERSION = 'v40'
21
+ RECURRING_API_VERSION = 'v30'
21
22
 
22
23
  STANDARD_ERROR_CODE_MAPPING = {
23
24
  '101' => STANDARD_ERROR_CODE[:incorrect_number],
@@ -57,6 +58,7 @@ module ActiveMerchant #:nodoc:
57
58
  add_installments(post, options) if options[:installments]
58
59
  add_3ds(post, options)
59
60
  add_3ds_authenticated_data(post, options)
61
+ add_splits(post, options)
60
62
  commit('authorise', post, options)
61
63
  end
62
64
 
@@ -64,6 +66,7 @@ module ActiveMerchant #:nodoc:
64
66
  post = init_post(options)
65
67
  add_invoice_for_modification(post, money, options)
66
68
  add_reference(post, authorization, options)
69
+ add_splits(post, options)
67
70
  commit('capture', post, options)
68
71
  end
69
72
 
@@ -71,6 +74,7 @@ module ActiveMerchant #:nodoc:
71
74
  post = init_post(options)
72
75
  add_invoice_for_modification(post, money, options)
73
76
  add_original_reference(post, authorization, options)
77
+ add_splits(post, options)
74
78
  commit('refund', post, options)
75
79
  end
76
80
 
@@ -98,7 +102,9 @@ module ActiveMerchant #:nodoc:
98
102
  add_recurring_contract(post, options)
99
103
  add_address(post, options)
100
104
 
101
- initial_response = commit('authorise', post, options)
105
+ action = options[:tokenize_only] ? 'storeToken' : 'authorise'
106
+
107
+ initial_response = commit(action, post, options)
102
108
 
103
109
  if initial_response.success? && card_not_stored?(initial_response)
104
110
  unsupported_failure_response(initial_response)
@@ -107,6 +113,17 @@ module ActiveMerchant #:nodoc:
107
113
  end
108
114
  end
109
115
 
116
+ def unstore(options={})
117
+ requires!(options, :shopper_reference, :recurring_detail_reference)
118
+ post = {}
119
+
120
+ add_shopper_reference(post, options)
121
+ add_merchant_account(post, options)
122
+ post[:recurringDetailReference] = options[:recurring_detail_reference]
123
+
124
+ commit('disable', post, options)
125
+ end
126
+
110
127
  def verify(credit_card, options={})
111
128
  MultiResponse.run(:use_first_response) do |r|
112
129
  r.process { authorize(0, credit_card, options) }
@@ -179,7 +196,6 @@ module ActiveMerchant #:nodoc:
179
196
  post[:telephoneNumber] = options[:billing_address][:phone] if options.dig(:billing_address, :phone)
180
197
  post[:shopperEmail] = options[:shopper_email] if options[:shopper_email]
181
198
  post[:shopperIP] = options[:shopper_ip] if options[:shopper_ip]
182
- post[:shopperReference] = options[:shopper_reference] if options[:shopper_reference]
183
199
  post[:shopperStatement] = options[:shopper_statement] if options[:shopper_statement]
184
200
  post[:fraudOffset] = options[:fraud_offset] if options[:fraud_offset]
185
201
  post[:selectedBrand] = options[:selected_brand] if options[:selected_brand]
@@ -198,6 +214,7 @@ module ActiveMerchant #:nodoc:
198
214
  post[:additionalData][:RequestedTestAcquirerResponseCode] = options[:requested_test_acquirer_response_code] if options[:requested_test_acquirer_response_code] && test?
199
215
  post[:deviceFingerprint] = options[:device_fingerprint] if options[:device_fingerprint]
200
216
  add_risk_data(post, options)
217
+ add_shopper_reference(post, options)
201
218
  end
202
219
 
203
220
  def add_risk_data(post, options)
@@ -207,11 +224,39 @@ module ActiveMerchant #:nodoc:
207
224
  end
208
225
  end
209
226
 
227
+ def add_splits(post, options)
228
+ return unless split_data = options[:splits]
229
+ splits = []
230
+ split_data.each do |split|
231
+ amount = {
232
+ value: split['amount']['value'],
233
+ }
234
+ amount[:currency] = split['amount']['currency'] if split['amount']['currency']
235
+
236
+ split_hash = {
237
+ amount: amount,
238
+ type: split['type'],
239
+ reference: split['reference']
240
+ }
241
+ split_hash['account'] = split['account'] if split['account']
242
+ splits.push(split_hash)
243
+ end
244
+ post[:splits] = splits
245
+ end
246
+
210
247
  def add_stored_credentials(post, payment, options)
211
248
  add_shopper_interaction(post, payment, options)
212
249
  add_recurring_processing_model(post, options)
213
250
  end
214
251
 
252
+ def add_merchant_account(post, options)
253
+ post[:merchantAccount] = options[:merchant_account] || @merchant_account
254
+ end
255
+
256
+ def add_shopper_reference(post, options)
257
+ post[:shopperReference] = options[:shopper_reference] if options[:shopper_reference]
258
+ end
259
+
215
260
  def add_shopper_interaction(post, payment, options={})
216
261
  if options.dig(:stored_credential, :initial_transaction) || (payment.respond_to?(:verification_value) && payment.verification_value) || payment.is_a?(NetworkTokenizationCreditCard)
217
262
  shopper_interaction = 'Ecommerce'
@@ -401,7 +446,7 @@ module ActiveMerchant #:nodoc:
401
446
 
402
447
  def commit(action, parameters, options)
403
448
  begin
404
- raw_response = ssl_post("#{url}/#{action}", post_data(action, parameters), request_headers(options))
449
+ raw_response = ssl_post(url(action), post_data(action, parameters), request_headers(options))
405
450
  response = parse(raw_response)
406
451
  rescue ResponseError => e
407
452
  raw_response = e.response.body
@@ -428,13 +473,18 @@ module ActiveMerchant #:nodoc:
428
473
  CVC_MAPPING[response['additionalData']['cvcResult'][0]] if response.dig('additionalData', 'cvcResult')
429
474
  end
430
475
 
431
- def url
476
+ def endpoint(action)
477
+ recurring = %w(disable storeToken).include?(action)
478
+ recurring ? "Recurring/#{RECURRING_API_VERSION}/#{action}" : "Payment/#{PAYMENT_API_VERSION}/#{action}"
479
+ end
480
+
481
+ def url(action)
432
482
  if test?
433
- "#{test_url}#{API_VERSION}"
483
+ "#{test_url}#{endpoint(action)}"
434
484
  elsif @options[:subdomain]
435
- "https://#{@options[:subdomain]}-pal-live.adyenpayments.com/pal/servlet/Payment/#{API_VERSION}"
485
+ "https://#{@options[:subdomain]}-pal-live.adyenpayments.com/pal/servlet/#{endpoint(action)}"
436
486
  else
437
- "#{live_url}#{API_VERSION}"
487
+ "#{live_url}#{endpoint(action)}"
438
488
  end
439
489
  end
440
490
 
@@ -459,6 +509,8 @@ module ActiveMerchant #:nodoc:
459
509
  response['response'] == "[#{action}-received]"
460
510
  when 'adjustAuthorisation'
461
511
  response['response'] == 'Authorised' || response['response'] == '[adjustAuthorisation-received]'
512
+ when 'storeToken'
513
+ response['result'] == 'Success'
462
514
  else
463
515
  false
464
516
  end
@@ -466,26 +518,29 @@ module ActiveMerchant #:nodoc:
466
518
 
467
519
  def message_from(action, response)
468
520
  return authorize_message_from(response) if action.to_s == 'authorise' || action.to_s == 'authorise3d'
469
- response['response'] || response['message']
521
+ response['response'] || response['message'] || response['result']
470
522
  end
471
523
 
472
524
  def authorize_message_from(response)
473
525
  if response['refusalReason'] && response['additionalData'] && response['additionalData']['refusalReasonRaw']
474
526
  "#{response['refusalReason']} | #{response['additionalData']['refusalReasonRaw']}"
475
527
  else
476
- response['refusalReason'] || response['resultCode'] || response['message']
528
+ response['refusalReason'] || response['resultCode'] || response['message'] || response['result']
477
529
  end
478
530
  end
479
531
 
480
532
  def authorization_from(action, parameters, response)
481
533
  return nil if response['pspReference'].nil?
534
+
482
535
  recurring = response['additionalData']['recurring.recurringDetailReference'] if response['additionalData']
536
+ recurring = response['recurringDetailReference'] if action == 'storeToken'
537
+
483
538
  "#{parameters[:originalReference]}##{response['pspReference']}##{recurring}"
484
539
  end
485
540
 
486
541
  def init_post(options = {})
487
542
  post = {}
488
- post[:merchantAccount] = options[:merchant_account] || @merchant_account
543
+ add_merchant_account(post, options)
489
544
  post[:reference] = options[:order_id] if options[:order_id]
490
545
  post
491
546
  end
@@ -359,6 +359,12 @@ module ActiveMerchant #:nodoc:
359
359
  add_browser_info(three_ds_2_options[:browser_info], post)
360
360
  post[:threeDS2RequestData] = { deviceChannel: device_channel, notificationURL: three_ds_2_options[:notification_url] }
361
361
  end
362
+
363
+ if options.has_key?(:execute_threed)
364
+ post[:additionalData] ||= {}
365
+ post[:additionalData][:executeThreeD] = options[:execute_threed]
366
+ post[:additionalData][:scaExemption] = options[:sca_exemption] if options[:sca_exemption]
367
+ end
362
368
  else
363
369
  return unless options[:execute_threed] || options[:threed_dynamic]
364
370
  post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] }
@@ -187,8 +187,13 @@ module ActiveMerchant #:nodoc:
187
187
  add_echo(post, options)
188
188
  add_submerchant_id(post, options)
189
189
  add_processor(post, options)
190
+ add_email(post, options)
190
191
 
191
- commit(:refund, post)
192
+ if options[:referral_cft]
193
+ commit(:referral_cft, post)
194
+ else
195
+ commit(:refund, post)
196
+ end
192
197
  end
193
198
 
194
199
  def credit(amount, payment_method, options={})
@@ -372,7 +377,8 @@ module ActiveMerchant #:nodoc:
372
377
  purchase_void: '7',
373
378
  refund_void: '8',
374
379
  capture_void: '9',
375
- threeds_completion: '92'
380
+ threeds_completion: '92',
381
+ referral_cft: '34'
376
382
  }
377
383
 
378
384
  def commit(action, params, reference_action = nil)
@@ -288,6 +288,7 @@ module ActiveMerchant #:nodoc:
288
288
 
289
289
  xml = Builder::XmlMarkup.new :indent => 2
290
290
  add_purchase_data(xml, money, true, options)
291
+ add_mdd_fields(xml, options)
291
292
  add_capture_service(xml, request_id, request_token)
292
293
  add_business_rules_data(xml, authorization, options)
293
294
  add_issuer_additional_data(xml, options)
@@ -468,7 +469,7 @@ module ActiveMerchant #:nodoc:
468
469
  xml.tag! 'company', address[:company] unless address[:company].blank?
469
470
  xml.tag! 'companyTaxID', address[:companyTaxID] unless address[:company_tax_id].blank?
470
471
  xml.tag! 'phoneNumber', address[:phone] unless address[:phone].blank?
471
- xml.tag! 'email', options[:email] || 'null@cybersource.com'
472
+ xml.tag! 'email', options[:email].presence || 'null@cybersource.com'
472
473
  xml.tag! 'ipAddress', options[:ip] unless options[:ip].blank? || shipTo
473
474
  xml.tag! 'driversLicenseNumber', options[:drivers_license_number] unless options[:drivers_license_number].blank?
474
475
  xml.tag! 'driversLicenseState', options[:drivers_license_state] unless options[:drivers_license_state].blank?
@@ -32,7 +32,7 @@ module ActiveMerchant #:nodoc:
32
32
 
33
33
  def capture(money, authorization, options={})
34
34
  post = {}
35
- post[:payment_id] = authorization
35
+ post[:authorization_id] = authorization
36
36
  add_invoice(post, money, options) if money
37
37
  commit('capture', post, options)
38
38
  end
@@ -47,7 +47,7 @@ module ActiveMerchant #:nodoc:
47
47
 
48
48
  def void(authorization, options={})
49
49
  post = {}
50
- post[:payment_id] = authorization
50
+ post[:authorization_id] = authorization
51
51
  commit('void', post, options)
52
52
  end
53
53
 
@@ -193,9 +193,9 @@ module ActiveMerchant #:nodoc:
193
193
  when 'refund'
194
194
  'refunds'
195
195
  when 'capture'
196
- "payments/#{parameters[:payment_id]}/capture"
196
+ 'payments'
197
197
  when 'void'
198
- "payments/#{parameters[:payment_id]}/cancel"
198
+ "payments/#{parameters[:authorization_id]}/cancel"
199
199
  end
200
200
  end
201
201
 
@@ -145,6 +145,7 @@ module ActiveMerchant #:nodoc:
145
145
  xml.transactionId new_transaction_id
146
146
 
147
147
  add_customer_data(xml, options)
148
+ add_extra_data(xml, options[:extra_data]) if options[:extra_data]
148
149
 
149
150
  xml.amount localized_amount(money, currency)
150
151
  xml.currency currency
@@ -162,6 +163,7 @@ module ActiveMerchant #:nodoc:
162
163
  xml.transactionId new_transaction_id
163
164
 
164
165
  add_customer_data(xml, options)
166
+ add_extra_data(xml, options[:extra_data]) if options[:extra_data]
165
167
 
166
168
  xml.amount localized_amount(money, currency)
167
169
  xml.currency currency
@@ -174,17 +176,19 @@ module ActiveMerchant #:nodoc:
174
176
  currency = options[:currency] || currency(money)
175
177
 
176
178
  xml.refund do
177
- xml.transactionId new_transaction_id
178
- xml.referenceTransactionId authorization&.split('|')&.first
179
- xml.amount localized_amount(money, currency)
180
- xml.currency currency
179
+ xml.transactionId new_transaction_id
180
+ add_extra_data(xml, options[:extra_data]) if options[:extra_data]
181
+ xml.referenceTransactionId authorization&.split('|')&.first
182
+ xml.amount localized_amount(money, currency)
183
+ xml.currency currency
181
184
  end
182
185
  end
183
186
 
184
187
  def add_void(xml, authorization)
185
188
  xml.void do
186
- xml.transactionId new_transaction_id
187
- xml.referenceTransactionId authorization&.split('|')&.first
189
+ xml.transactionId new_transaction_id
190
+ add_extra_data(xml, options[:extra_data]) if options[:extra_data]
191
+ xml.referenceTransactionId authorization&.split('|')&.first
188
192
  end
189
193
  end
190
194
 
@@ -192,10 +196,11 @@ module ActiveMerchant #:nodoc:
192
196
  currency = options[:currency] || currency(money)
193
197
 
194
198
  xml.capture_ do
195
- xml.transactionId new_transaction_id
196
- xml.referenceTransactionId authorization&.split('|')&.first
197
- xml.amount localized_amount(money, currency)
198
- xml.currency currency
199
+ xml.transactionId new_transaction_id
200
+ add_extra_data(xml, options[:extra_data]) if options[:extra_data]
201
+ xml.referenceTransactionId authorization&.split('|')&.first
202
+ xml.amount localized_amount(money, currency)
203
+ xml.currency currency
199
204
  end
200
205
  end
201
206
 
@@ -246,6 +251,12 @@ module ActiveMerchant #:nodoc:
246
251
  SecureRandom.uuid
247
252
  end
248
253
 
254
+ def add_extra_data(xml, extra_data)
255
+ extra_data.each do |k, v|
256
+ xml.extraData(v, key: k)
257
+ end
258
+ end
259
+
249
260
  def commit(request)
250
261
  url = (test? ? test_url : live_url)
251
262
 
@@ -321,7 +321,7 @@ module ActiveMerchant #:nodoc:
321
321
  def success?(response)
322
322
  return FRAUD_WARNING_CODES.concat(['0']).include?(response['errors'].first['code']) if response['errors']
323
323
 
324
- !['DECLINED', 'CANCELLED'].include?(response['status']) && !['AuthenticationFailed'].include?(response['code'])
324
+ !['DECLINED', 'CANCELLED'].include?(response['status']) && !['AuthenticationFailed', 'AuthorizationFailed'].include?(response['code'])
325
325
  end
326
326
 
327
327
  def message_from(response)
@@ -329,7 +329,11 @@ module ActiveMerchant #:nodoc:
329
329
  end
330
330
 
331
331
  def errors_from(response)
332
- response['errors'].present? ? STANDARD_ERROR_CODE_MAPPING[response['errors'].first['code']] : ''
332
+ if ['AuthenticationFailed', 'AuthorizationFailed'].include?(response['code'])
333
+ response['code']
334
+ else
335
+ response['errors'].present? ? STANDARD_ERROR_CODE_MAPPING[response['errors'].first['code']] : ''
336
+ end
333
337
  end
334
338
 
335
339
  def authorization_from(response, headers = {})
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = '1.102.0'
2
+ VERSION = '1.103.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemerchant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.102.0
4
+ version: 1.103.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-14 00:00:00.000000000 Z
11
+ date: 2019-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport