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 +4 -4
- data/CHANGELOG +12 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +69 -14
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +6 -0
- data/lib/active_merchant/billing/gateways/credorax.rb +8 -2
- data/lib/active_merchant/billing/gateways/cyber_source.rb +2 -1
- data/lib/active_merchant/billing/gateways/d_local.rb +4 -4
- data/lib/active_merchant/billing/gateways/ixopay.rb +21 -10
- data/lib/active_merchant/billing/gateways/quickbooks.rb +6 -2
- data/lib/active_merchant/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a51e307707d9ffa9cd0d32779623b7095ea9af27f16078de9736be65fc8c0090
|
4
|
+
data.tar.gz: 27b16b69f6bb974795ddc1fae4d924257bee5c0620d0ab009b771b107d59be24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
8
|
-
self.live_url = 'https://pal-live.adyen.com/pal/servlet/
|
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 =
|
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
|
-
|
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
|
-
|
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(
|
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
|
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}#{
|
483
|
+
"#{test_url}#{endpoint(action)}"
|
434
484
|
elsif @options[:subdomain]
|
435
|
-
"https://#{@options[:subdomain]}-pal-live.adyenpayments.com/pal/servlet
|
485
|
+
"https://#{@options[:subdomain]}-pal-live.adyenpayments.com/pal/servlet/#{endpoint(action)}"
|
436
486
|
else
|
437
|
-
"#{live_url}#{
|
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
|
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
|
-
|
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[:
|
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[:
|
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
|
-
|
196
|
+
'payments'
|
197
197
|
when 'void'
|
198
|
-
"payments/#{parameters[:
|
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
|
178
|
-
xml
|
179
|
-
xml.
|
180
|
-
xml.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
|
187
|
-
xml
|
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
|
196
|
-
xml
|
197
|
-
xml.
|
198
|
-
xml.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
|
-
|
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 = {})
|
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.
|
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
|
+
date: 2019-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|