activemerchant 1.102.0 → 1.103.0

Sign up to get free protection for your applications and to get access to all the features.
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