stripe 4.9.0 → 5.1.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/.editorconfig +10 -0
- data/.rubocop.yml +28 -4
- data/.rubocop_todo.yml +11 -22
- data/.travis.yml +3 -6
- data/.vscode/extensions.json +7 -0
- data/.vscode/settings.json +8 -0
- data/CHANGELOG.md +102 -2
- data/Gemfile +2 -10
- data/README.md +96 -40
- data/Rakefile +8 -7
- data/VERSION +1 -1
- data/lib/stripe.rb +64 -85
- data/lib/stripe/api_operations/delete.rb +23 -1
- data/lib/stripe/api_operations/list.rb +0 -6
- data/lib/stripe/api_operations/nested_resource.rb +14 -7
- data/lib/stripe/api_operations/request.rb +3 -7
- data/lib/stripe/api_operations/save.rb +1 -3
- data/lib/stripe/api_resource.rb +50 -2
- data/lib/stripe/connection_manager.rb +141 -0
- data/lib/stripe/error_object.rb +94 -0
- data/lib/stripe/errors.rb +22 -9
- data/lib/stripe/list_object.rb +11 -5
- data/lib/stripe/multipart_encoder.rb +131 -0
- data/lib/stripe/object_types.rb +94 -0
- data/lib/stripe/resources.rb +77 -0
- data/lib/stripe/{account.rb → resources/account.rb} +49 -27
- data/lib/stripe/{account_link.rb → resources/account_link.rb} +1 -1
- data/lib/stripe/resources/alipay_account.rb +34 -0
- data/lib/stripe/{apple_pay_domain.rb → resources/apple_pay_domain.rb} +1 -1
- data/lib/stripe/resources/application_fee.rb +13 -0
- data/lib/stripe/resources/application_fee_refund.rb +30 -0
- data/lib/stripe/{balance.rb → resources/balance.rb} +1 -1
- data/lib/stripe/{balance_transaction.rb → resources/balance_transaction.rb} +1 -5
- data/lib/stripe/{bank_account.rb → resources/bank_account.rb} +14 -4
- data/lib/stripe/{bitcoin_receiver.rb → resources/bitcoin_receiver.rb} +3 -3
- data/lib/stripe/{bitcoin_transaction.rb → resources/bitcoin_transaction.rb} +1 -1
- data/lib/stripe/resources/capability.rb +33 -0
- data/lib/stripe/{card.rb → resources/card.rb} +12 -4
- data/lib/stripe/resources/charge.rb +22 -0
- data/lib/stripe/{checkout → resources/checkout}/session.rb +2 -2
- data/lib/stripe/{country_spec.rb → resources/country_spec.rb} +1 -1
- data/lib/stripe/{coupon.rb → resources/coupon.rb} +2 -2
- data/lib/stripe/resources/credit_note.rb +22 -0
- data/lib/stripe/resources/customer.rb +35 -0
- data/lib/stripe/resources/customer_balance_transaction.rb +30 -0
- data/lib/stripe/resources/discount.rb +7 -0
- data/lib/stripe/{dispute.rb → resources/dispute.rb} +9 -7
- data/lib/stripe/{ephemeral_key.rb → resources/ephemeral_key.rb} +5 -2
- data/lib/stripe/{event.rb → resources/event.rb} +1 -1
- data/lib/stripe/{exchange_rate.rb → resources/exchange_rate.rb} +1 -1
- data/lib/stripe/{file.rb → resources/file.rb} +8 -11
- data/lib/stripe/{file_link.rb → resources/file_link.rb} +2 -2
- data/lib/stripe/resources/invoice.rb +73 -0
- data/lib/stripe/{invoice_item.rb → resources/invoice_item.rb} +2 -2
- data/lib/stripe/{invoice_line_item.rb → resources/invoice_line_item.rb} +1 -1
- data/lib/stripe/resources/issuing/authorization.rb +33 -0
- data/lib/stripe/resources/issuing/card.rb +24 -0
- data/lib/stripe/{issuing → resources/issuing}/card_details.rb +1 -1
- data/lib/stripe/{issuing → resources/issuing}/cardholder.rb +2 -2
- data/lib/stripe/{issuing → resources/issuing}/dispute.rb +2 -2
- data/lib/stripe/{issuing → resources/issuing}/transaction.rb +2 -2
- data/lib/stripe/resources/login_link.rb +14 -0
- data/lib/stripe/resources/order.rb +32 -0
- data/lib/stripe/{order_return.rb → resources/order_return.rb} +1 -1
- data/lib/stripe/resources/payment_intent.rb +42 -0
- data/lib/stripe/resources/payment_method.rb +32 -0
- data/lib/stripe/resources/payout.rb +22 -0
- data/lib/stripe/{person.rb → resources/person.rb} +8 -3
- data/lib/stripe/{plan.rb → resources/plan.rb} +1 -1
- data/lib/stripe/{product.rb → resources/product.rb} +3 -3
- data/lib/stripe/resources/radar/early_fraud_warning.rb +11 -0
- data/lib/stripe/{radar → resources/radar}/value_list.rb +2 -2
- data/lib/stripe/{radar → resources/radar}/value_list_item.rb +2 -2
- data/lib/stripe/{recipient.rb → resources/recipient.rb} +2 -6
- data/lib/stripe/{recipient_transfer.rb → resources/recipient_transfer.rb} +1 -1
- data/lib/stripe/{refund.rb → resources/refund.rb} +1 -1
- data/lib/stripe/{reporting → resources/reporting}/report_run.rb +2 -2
- data/lib/stripe/{reporting → resources/reporting}/report_type.rb +2 -2
- data/lib/stripe/resources/reversal.rb +29 -0
- data/lib/stripe/resources/review.rb +20 -0
- data/lib/stripe/resources/setup_intent.rb +32 -0
- data/lib/stripe/{sigma → resources/sigma}/scheduled_query_run.rb +2 -2
- data/lib/stripe/{sku.rb → resources/sku.rb} +3 -3
- data/lib/stripe/{source.rb → resources/source.rb} +17 -15
- data/lib/stripe/{source_transaction.rb → resources/source_transaction.rb} +1 -1
- data/lib/stripe/resources/subscription.rb +25 -0
- data/lib/stripe/{subscription_item.rb → resources/subscription_item.rb} +5 -2
- data/lib/stripe/resources/subscription_schedule.rb +32 -0
- data/lib/stripe/resources/tax_id.rb +26 -0
- data/lib/stripe/resources/tax_rate.rb +11 -0
- data/lib/stripe/{terminal → resources/terminal}/connection_token.rb +2 -2
- data/lib/stripe/{terminal → resources/terminal}/location.rb +3 -2
- data/lib/stripe/{terminal → resources/terminal}/reader.rb +3 -2
- data/lib/stripe/{three_d_secure.rb → resources/three_d_secure.rb} +1 -1
- data/lib/stripe/{token.rb → resources/token.rb} +1 -1
- data/lib/stripe/resources/topup.rb +22 -0
- data/lib/stripe/resources/transfer.rb +26 -0
- data/lib/stripe/resources/usage_record.rb +7 -0
- data/lib/stripe/{usage_record_summary.rb → resources/usage_record_summary.rb} +1 -1
- data/lib/stripe/{webhook_endpoint.rb → resources/webhook_endpoint.rb} +2 -2
- data/lib/stripe/singleton_api_resource.rb +3 -1
- data/lib/stripe/stripe_client.rb +347 -218
- data/lib/stripe/stripe_object.rb +72 -59
- data/lib/stripe/stripe_response.rb +53 -21
- data/lib/stripe/util.rb +54 -109
- data/lib/stripe/version.rb +1 -1
- data/lib/stripe/webhook.rb +5 -3
- data/stripe.gemspec +14 -5
- data/test/stripe/account_link_test.rb +1 -1
- data/test/stripe/account_test.rb +193 -32
- data/test/stripe/alipay_account_test.rb +1 -1
- data/test/stripe/api_operations_test.rb +3 -4
- data/test/stripe/api_resource_test.rb +119 -30
- data/test/stripe/apple_pay_domain_test.rb +18 -5
- data/test/stripe/application_fee_refund_test.rb +1 -1
- data/test/stripe/application_fee_test.rb +45 -1
- data/test/stripe/balance_test.rb +1 -1
- data/test/stripe/balance_transaction_test.rb +20 -0
- data/test/stripe/bank_account_test.rb +1 -1
- data/test/stripe/capability_test.rb +45 -0
- data/test/stripe/charge_test.rb +13 -8
- data/test/stripe/checkout/session_test.rb +7 -1
- data/test/stripe/connection_manager_test.rb +138 -0
- data/test/stripe/country_spec_test.rb +1 -1
- data/test/stripe/coupon_test.rb +16 -6
- data/test/stripe/credit_note_test.rb +61 -0
- data/test/stripe/customer_balance_transaction_test.rb +37 -0
- data/test/stripe/customer_card_test.rb +1 -1
- data/test/stripe/customer_test.rb +151 -40
- data/test/stripe/dispute_test.rb +10 -1
- data/test/stripe/ephemeral_key_test.rb +8 -1
- data/test/stripe/errors_test.rb +30 -9
- data/test/stripe/exchange_rate_test.rb +1 -1
- data/test/stripe/file_link_test.rb +1 -1
- data/test/stripe/file_test.rb +19 -5
- data/test/stripe/invoice_item_test.rb +18 -7
- data/test/stripe/invoice_line_item_test.rb +1 -1
- data/test/stripe/invoice_test.rb +77 -9
- data/test/stripe/issuing/authorization_test.rb +33 -11
- data/test/stripe/issuing/card_test.rb +15 -6
- data/test/stripe/issuing/cardholder_test.rb +1 -1
- data/test/stripe/issuing/dispute_test.rb +1 -1
- data/test/stripe/issuing/transaction_test.rb +1 -1
- data/test/stripe/list_object_test.rb +1 -17
- data/test/stripe/login_link_test.rb +2 -2
- data/test/stripe/multipart_encoder_test.rb +130 -0
- data/test/stripe/oauth_test.rb +1 -1
- data/test/stripe/order_return_test.rb +1 -1
- data/test/stripe/order_test.rb +28 -3
- data/test/stripe/payment_intent_test.rb +31 -4
- data/test/stripe/payment_method_test.rb +84 -0
- data/test/stripe/payout_test.rb +8 -1
- data/test/stripe/person_test.rb +1 -1
- data/test/stripe/plan_test.rb +26 -20
- data/test/stripe/product_test.rb +16 -6
- data/test/stripe/radar/early_fraud_warning_test.rb +22 -0
- data/test/stripe/radar/value_list_item_test.rb +16 -6
- data/test/stripe/radar/value_list_test.rb +16 -6
- data/test/stripe/recipient_test.rb +18 -5
- data/test/stripe/refund_test.rb +1 -1
- data/test/stripe/reporting/report_run_test.rb +1 -1
- data/test/stripe/reporting/report_type_test.rb +1 -1
- data/test/stripe/reversal_test.rb +1 -1
- data/test/stripe/review_test.rb +1 -1
- data/test/stripe/setup_intent_test.rb +84 -0
- data/test/stripe/sigma/scheduled_query_run_test.rb +1 -1
- data/test/stripe/sku_test.rb +16 -6
- data/test/stripe/source_test.rb +14 -19
- data/test/stripe/source_transaction_test.rb +1 -1
- data/test/stripe/stripe_client_test.rb +242 -26
- data/test/stripe/stripe_object_test.rb +8 -36
- data/test/stripe/stripe_response_test.rb +71 -25
- data/test/stripe/subscription_item_test.rb +28 -6
- data/test/stripe/subscription_schedule_test.rb +19 -1
- data/test/stripe/subscription_test.rb +29 -9
- data/test/stripe/tax_id_test.rb +31 -0
- data/test/stripe/tax_rate_test.rb +43 -0
- data/test/stripe/terminal/connection_token_test.rb +1 -1
- data/test/stripe/terminal/location_test.rb +18 -1
- data/test/stripe/terminal/reader_test.rb +18 -1
- data/test/stripe/three_d_secure_test.rb +1 -1
- data/test/stripe/topup_test.rb +9 -1
- data/test/stripe/transfer_test.rb +46 -1
- data/test/stripe/usage_record_summary_test.rb +1 -1
- data/test/stripe/util_test.rb +1 -1
- data/test/stripe/webhook_endpoint_test.rb +18 -1
- data/test/stripe/webhook_test.rb +4 -4
- data/test/stripe_mock.rb +4 -3
- data/test/stripe_test.rb +1 -14
- data/test/test_helper.rb +14 -11
- metadata +117 -125
- data/lib/stripe/alipay_account.rb +0 -27
- data/lib/stripe/application_fee.rb +0 -23
- data/lib/stripe/application_fee_refund.rb +0 -22
- data/lib/stripe/charge.rb +0 -84
- data/lib/stripe/customer.rb +0 -90
- data/lib/stripe/invoice.rb +0 -48
- data/lib/stripe/issuer_fraud_record.rb +0 -9
- data/lib/stripe/issuing/authorization.rb +0 -22
- data/lib/stripe/issuing/card.rb +0 -18
- data/lib/stripe/login_link.rb +0 -11
- data/lib/stripe/order.rb +0 -31
- data/lib/stripe/payment_intent.rb +0 -26
- data/lib/stripe/payout.rb +0 -20
- data/lib/stripe/reversal.rb +0 -22
- data/lib/stripe/review.rb +0 -14
- data/lib/stripe/subscription.rb +0 -25
- data/lib/stripe/subscription_schedule.rb +0 -32
- data/lib/stripe/subscription_schedule_revision.rb +0 -25
- data/lib/stripe/topup.rb +0 -16
- data/lib/stripe/transfer.rb +0 -23
- data/lib/stripe/usage_record.rb +0 -14
- data/test/stripe/account_external_accounts_operations_test.rb +0 -69
- data/test/stripe/account_login_links_operations_test.rb +0 -21
- data/test/stripe/account_persons_operations_test.rb +0 -70
- data/test/stripe/application_fee_refunds_operations_test.rb +0 -56
- data/test/stripe/customer_sources_operations_test.rb +0 -64
- data/test/stripe/file_upload_test.rb +0 -76
- data/test/stripe/issuer_fraud_record_test.rb +0 -20
- data/test/stripe/subscription_schedule_revision_test.rb +0 -37
- data/test/stripe/subscription_schedule_revisions_operations_test.rb +0 -35
- data/test/stripe/transfer_reversals_operations_test.rb +0 -57
- data/test/stripe/usage_record_test.rb +0 -28
data/lib/stripe/stripe_object.rb
CHANGED
@@ -4,7 +4,7 @@ module Stripe
|
|
4
4
|
class StripeObject
|
5
5
|
include Enumerable
|
6
6
|
|
7
|
-
@@permanent_attributes = Set.new([:id])
|
7
|
+
@@permanent_attributes = Set.new([:id]) # rubocop:disable Style/ClassVars
|
8
8
|
|
9
9
|
# The default :id method is deprecated and isn't useful to us
|
10
10
|
undef :id if method_defined?(:id)
|
@@ -93,10 +93,12 @@ module Stripe
|
|
93
93
|
# considered to be equal if they have the same set of values and each one
|
94
94
|
# of those values is the same.
|
95
95
|
def ==(other)
|
96
|
-
other.is_a?(StripeObject) &&
|
96
|
+
other.is_a?(StripeObject) &&
|
97
|
+
@values == other.instance_variable_get(:@values)
|
97
98
|
end
|
98
99
|
|
99
|
-
# Hash equality. As with `#==`, we consider two equivalent Stripe objects
|
100
|
+
# Hash equality. As with `#==`, we consider two equivalent Stripe objects
|
101
|
+
# equal.
|
100
102
|
def eql?(other)
|
101
103
|
# Defer to the implementation on `#==`.
|
102
104
|
self == other
|
@@ -121,21 +123,10 @@ module Stripe
|
|
121
123
|
|
122
124
|
def inspect
|
123
125
|
id_string = respond_to?(:id) && !id.nil? ? " id=#{id}" : ""
|
124
|
-
"#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " +
|
126
|
+
"#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " +
|
127
|
+
JSON.pretty_generate(@values)
|
125
128
|
end
|
126
129
|
|
127
|
-
# Re-initializes the object based on a hash of values (usually one that's
|
128
|
-
# come back from an API call). Adds or removes value accessors as necessary
|
129
|
-
# and updates the state of internal data.
|
130
|
-
#
|
131
|
-
# Please don't use this method. If you're trying to do mass assignment, try
|
132
|
-
# #initialize_from instead.
|
133
|
-
def refresh_from(values, opts, partial = false)
|
134
|
-
initialize_from(values, opts, partial)
|
135
|
-
end
|
136
|
-
extend Gem::Deprecate
|
137
|
-
deprecate :refresh_from, "#update_attributes", 2016, 1
|
138
|
-
|
139
130
|
# Mass assigns attributes on the model.
|
140
131
|
#
|
141
132
|
# This is a version of +update_attributes+ that takes some extra options
|
@@ -162,12 +153,12 @@ module Stripe
|
|
162
153
|
end
|
163
154
|
end
|
164
155
|
|
165
|
-
def [](
|
166
|
-
@values[
|
156
|
+
def [](key)
|
157
|
+
@values[key.to_sym]
|
167
158
|
end
|
168
159
|
|
169
|
-
def []=(
|
170
|
-
send(:"#{
|
160
|
+
def []=(key, value)
|
161
|
+
send(:"#{key}=", value)
|
171
162
|
end
|
172
163
|
|
173
164
|
def keys
|
@@ -178,17 +169,20 @@ module Stripe
|
|
178
169
|
@values.values
|
179
170
|
end
|
180
171
|
|
181
|
-
def to_json(*
|
172
|
+
def to_json(*_opts)
|
173
|
+
# TODO: pass opts to JSON.generate?
|
182
174
|
JSON.generate(@values)
|
183
175
|
end
|
184
176
|
|
185
|
-
def as_json(*
|
186
|
-
@values.as_json(*
|
177
|
+
def as_json(*opts)
|
178
|
+
@values.as_json(*opts)
|
187
179
|
end
|
188
180
|
|
189
181
|
def to_hash
|
190
182
|
maybe_to_hash = lambda do |value|
|
191
|
-
|
183
|
+
return nil if value.nil?
|
184
|
+
|
185
|
+
value.respond_to?(:to_hash) ? value.to_hash : value
|
192
186
|
end
|
193
187
|
|
194
188
|
@values.each_with_object({}) do |(key, value), acc|
|
@@ -251,10 +245,11 @@ module Stripe
|
|
251
245
|
# values within in that its parent StripeObject doesn't know about.
|
252
246
|
#
|
253
247
|
unsaved = @unsaved_values.include?(k)
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
248
|
+
next unless options[:force] || unsaved || v.is_a?(StripeObject)
|
249
|
+
|
250
|
+
update_hash[k.to_sym] = serialize_params_value(
|
251
|
+
@values[k], @original_values[k], unsaved, options[:force], key: k
|
252
|
+
)
|
258
253
|
end
|
259
254
|
|
260
255
|
# a `nil` that makes it out of `#serialize_params_value` signals an empty
|
@@ -264,16 +259,6 @@ module Stripe
|
|
264
259
|
update_hash
|
265
260
|
end
|
266
261
|
|
267
|
-
class << self
|
268
|
-
# This class method has been deprecated in favor of the instance method
|
269
|
-
# of the same name.
|
270
|
-
def serialize_params(obj, options = {})
|
271
|
-
obj.serialize_params(options)
|
272
|
-
end
|
273
|
-
extend Gem::Deprecate
|
274
|
-
deprecate :serialize_params, "#serialize_params", 2016, 9
|
275
|
-
end
|
276
|
-
|
277
262
|
# A protected field is one that doesn't get an accessor assigned to it
|
278
263
|
# (i.e. `obj.public = ...`) and one which is not allowed to be updated via
|
279
264
|
# the class level `Model.update(id, { ... })`.
|
@@ -281,13 +266,11 @@ module Stripe
|
|
281
266
|
[]
|
282
267
|
end
|
283
268
|
|
284
|
-
protected
|
285
|
-
|
286
|
-
def metaclass
|
269
|
+
protected def metaclass
|
287
270
|
class << self; self; end
|
288
271
|
end
|
289
272
|
|
290
|
-
def remove_accessors(keys)
|
273
|
+
protected def remove_accessors(keys)
|
291
274
|
# not available in the #instance_eval below
|
292
275
|
protected_fields = self.class.protected_fields
|
293
276
|
|
@@ -298,13 +281,31 @@ module Stripe
|
|
298
281
|
|
299
282
|
# Remove methods for the accessor's reader and writer.
|
300
283
|
[k, :"#{k}=", :"#{k}?"].each do |method_name|
|
301
|
-
|
284
|
+
next unless method_defined?(method_name)
|
285
|
+
|
286
|
+
begin
|
287
|
+
remove_method(method_name)
|
288
|
+
rescue NameError
|
289
|
+
# In some cases there can be a method that's detected with
|
290
|
+
# `method_defined?`, but which cannot be removed with
|
291
|
+
# `remove_method`, even though it's on the same class. The only
|
292
|
+
# case so far that we've noticed this is when a class is
|
293
|
+
# reopened for monkey patching:
|
294
|
+
#
|
295
|
+
# https://github.com/stripe/stripe-ruby/issues/749
|
296
|
+
#
|
297
|
+
# Here we swallow that error and issue a warning so at least
|
298
|
+
# the program doesn't crash.
|
299
|
+
warn("WARNING: Unable to remove method `#{method_name}`; " \
|
300
|
+
"if custom, please consider renaming to a name that doesn't " \
|
301
|
+
"collide with an API property name.")
|
302
|
+
end
|
302
303
|
end
|
303
304
|
end
|
304
305
|
end
|
305
306
|
end
|
306
307
|
|
307
|
-
def add_accessors(keys, values)
|
308
|
+
protected def add_accessors(keys, values)
|
308
309
|
# not available in the #instance_eval below
|
309
310
|
protected_fields = self.class.protected_fields
|
310
311
|
|
@@ -341,7 +342,11 @@ module Stripe
|
|
341
342
|
end
|
342
343
|
end
|
343
344
|
|
344
|
-
|
345
|
+
# Disabling the cop because it's confused by the fact that the methods are
|
346
|
+
# protected, but we do define `#respond_to_missing?` just below. Hopefully
|
347
|
+
# this is fixed in more recent Rubocop versions.
|
348
|
+
# rubocop:disable Style/MissingRespondToMissing
|
349
|
+
protected def method_missing(name, *args)
|
345
350
|
# TODO: only allow setting in updateable classes.
|
346
351
|
if name.to_s.end_with?("=")
|
347
352
|
attr = name.to_s[0...-1].to_sym
|
@@ -357,7 +362,9 @@ module Stripe
|
|
357
362
|
begin
|
358
363
|
mth = method(name)
|
359
364
|
rescue NameError
|
360
|
-
raise NoMethodError,
|
365
|
+
raise NoMethodError,
|
366
|
+
"Cannot set #{attr} on this object. HINT: you can't set: " \
|
367
|
+
"#{@@permanent_attributes.to_a.join(', ')}"
|
361
368
|
end
|
362
369
|
return mth.call(args[0])
|
363
370
|
elsif @values.key?(name)
|
@@ -372,11 +379,17 @@ module Stripe
|
|
372
379
|
# raise right away.
|
373
380
|
raise unless @transient_values.include?(name)
|
374
381
|
|
375
|
-
raise NoMethodError,
|
382
|
+
raise NoMethodError,
|
383
|
+
e.message + ". HINT: The '#{name}' attribute was set in the " \
|
384
|
+
"past, however. It was then wiped when refreshing the object " \
|
385
|
+
"with the result returned by Stripe's API, probably as a " \
|
386
|
+
"result of a save(). The attributes currently available on " \
|
387
|
+
"this object are: #{@values.keys.join(', ')}"
|
376
388
|
end
|
377
389
|
end
|
390
|
+
# rubocop:enable Style/MissingRespondToMissing
|
378
391
|
|
379
|
-
def respond_to_missing?(symbol, include_private = false)
|
392
|
+
protected def respond_to_missing?(symbol, include_private = false)
|
380
393
|
@values && @values.key?(symbol) || super
|
381
394
|
end
|
382
395
|
|
@@ -392,7 +405,7 @@ module Stripe
|
|
392
405
|
# * +:opts:+ Options for StripeObject like an API key.
|
393
406
|
# * +:partial:+ Indicates that the re-initialization should not attempt to
|
394
407
|
# remove accessors.
|
395
|
-
def initialize_from(values, opts, partial = false)
|
408
|
+
protected def initialize_from(values, opts, partial = false)
|
396
409
|
@opts = Util.normalize_opts(opts)
|
397
410
|
|
398
411
|
# the `#send` is here so that we can keep this method private
|
@@ -402,8 +415,8 @@ module Stripe
|
|
402
415
|
added = Set.new(values.keys - @values.keys)
|
403
416
|
|
404
417
|
# Wipe old state before setting new. This is useful for e.g. updating a
|
405
|
-
# customer, where there is no persistent card parameter. Mark those
|
406
|
-
# which don't persist as transient
|
418
|
+
# customer, where there is no persistent card parameter. Mark those
|
419
|
+
# values which don't persist as transient
|
407
420
|
|
408
421
|
remove_accessors(removed)
|
409
422
|
add_accessors(added, values)
|
@@ -423,7 +436,8 @@ module Stripe
|
|
423
436
|
self
|
424
437
|
end
|
425
438
|
|
426
|
-
def serialize_params_value(value, original, unsaved, force,
|
439
|
+
protected def serialize_params_value(value, original, unsaved, force,
|
440
|
+
key: nil)
|
427
441
|
if value.nil?
|
428
442
|
""
|
429
443
|
|
@@ -498,11 +512,9 @@ module Stripe
|
|
498
512
|
end
|
499
513
|
end
|
500
514
|
|
501
|
-
private
|
502
|
-
|
503
515
|
# Produces a deep copy of the given object including support for arrays,
|
504
516
|
# hashes, and StripeObjects.
|
505
|
-
def self.deep_copy(obj)
|
517
|
+
private_class_method def self.deep_copy(obj)
|
506
518
|
case obj
|
507
519
|
when Array
|
508
520
|
obj.map { |e| deep_copy(e) }
|
@@ -522,9 +534,8 @@ module Stripe
|
|
522
534
|
obj
|
523
535
|
end
|
524
536
|
end
|
525
|
-
private_class_method :deep_copy
|
526
537
|
|
527
|
-
def dirty_value!(value)
|
538
|
+
private def dirty_value!(value)
|
528
539
|
case value
|
529
540
|
when Array
|
530
541
|
value.map { |v| dirty_value!(v) }
|
@@ -535,12 +546,14 @@ module Stripe
|
|
535
546
|
|
536
547
|
# Returns a hash of empty values for all the values that are in the given
|
537
548
|
# StripeObject.
|
538
|
-
def empty_values(obj)
|
549
|
+
private def empty_values(obj)
|
539
550
|
values = case obj
|
540
551
|
when Hash then obj
|
541
552
|
when StripeObject then obj.instance_variable_get(:@values)
|
542
553
|
else
|
543
|
-
raise ArgumentError,
|
554
|
+
raise ArgumentError,
|
555
|
+
"#empty_values got unexpected object type: " \
|
556
|
+
"#{obj.class.name}"
|
544
557
|
end
|
545
558
|
|
546
559
|
values.each_with_object({}) do |(k, _), update|
|
@@ -4,6 +4,53 @@ module Stripe
|
|
4
4
|
# StripeResponse encapsulates some vitals of a response that came back from
|
5
5
|
# the Stripe API.
|
6
6
|
class StripeResponse
|
7
|
+
# Headers provides an access wrapper to an API response's header data. It
|
8
|
+
# mainly exists so that we don't need to expose the entire
|
9
|
+
# `Net::HTTPResponse` object while still getting some of its benefits like
|
10
|
+
# case-insensitive access to header names and flattening of header values.
|
11
|
+
class Headers
|
12
|
+
# Initializes a Headers object from a Net::HTTP::HTTPResponse object.
|
13
|
+
def self.from_net_http(resp)
|
14
|
+
new(resp.to_hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
# `hash` is expected to be a hash mapping header names to arrays of
|
18
|
+
# header values. This is the default format generated by calling
|
19
|
+
# `#to_hash` on a `Net::HTTPResponse` object because headers can be
|
20
|
+
# repeated multiple times. Using `#[]` will collapse values down to just
|
21
|
+
# the first.
|
22
|
+
def initialize(hash)
|
23
|
+
if !hash.is_a?(Hash) ||
|
24
|
+
!hash.keys.all? { |n| n.is_a?(String) } ||
|
25
|
+
!hash.values.all? { |a| a.is_a?(Array) } ||
|
26
|
+
!hash.values.all? { |a| a.all? { |v| v.is_a?(String) } }
|
27
|
+
raise ArgumentError,
|
28
|
+
"expect hash to be a map of string header names to arrays of " \
|
29
|
+
"header values"
|
30
|
+
end
|
31
|
+
|
32
|
+
@hash = {}
|
33
|
+
|
34
|
+
# This shouldn't be strictly necessary because `Net::HTTPResponse` will
|
35
|
+
# produce a hash with all headers downcased, but do it anyway just in
|
36
|
+
# case an object of this class was constructed manually.
|
37
|
+
#
|
38
|
+
# Also has the effect of duplicating the hash, which is desirable for a
|
39
|
+
# little extra object safety.
|
40
|
+
hash.each do |k, v|
|
41
|
+
@hash[k.downcase] = v
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def [](name)
|
46
|
+
values = @hash[name.downcase]
|
47
|
+
if values && values.count > 1
|
48
|
+
warn("Duplicate header values for `#{name}`; returning only first")
|
49
|
+
end
|
50
|
+
values ? values.first : nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
7
54
|
# The data contained by the HTTP body of the response deserialized from
|
8
55
|
# JSON.
|
9
56
|
attr_accessor :data
|
@@ -20,30 +67,15 @@ module Stripe
|
|
20
67
|
# The Stripe request ID of the response.
|
21
68
|
attr_accessor :request_id
|
22
69
|
|
23
|
-
# Initializes a StripeResponse object from a
|
24
|
-
#
|
25
|
-
|
26
|
-
# This may throw JSON::ParserError if the response body is not valid JSON.
|
27
|
-
def self.from_faraday_hash(http_resp)
|
28
|
-
resp = StripeResponse.new
|
29
|
-
resp.data = JSON.parse(http_resp[:body], symbolize_names: true)
|
30
|
-
resp.http_body = http_resp[:body]
|
31
|
-
resp.http_headers = http_resp[:headers]
|
32
|
-
resp.http_status = http_resp[:status]
|
33
|
-
resp.request_id = http_resp[:headers]["Request-Id"]
|
34
|
-
resp
|
35
|
-
end
|
36
|
-
|
37
|
-
# Initializes a StripeResponse object from a Faraday HTTP response object.
|
38
|
-
#
|
39
|
-
# This may throw JSON::ParserError if the response body is not valid JSON.
|
40
|
-
def self.from_faraday_response(http_resp)
|
70
|
+
# Initializes a StripeResponse object from a Net::HTTP::HTTPResponse
|
71
|
+
# object.
|
72
|
+
def self.from_net_http(http_resp)
|
41
73
|
resp = StripeResponse.new
|
42
74
|
resp.data = JSON.parse(http_resp.body, symbolize_names: true)
|
43
75
|
resp.http_body = http_resp.body
|
44
|
-
resp.http_headers = http_resp
|
45
|
-
resp.http_status = http_resp.
|
46
|
-
resp.request_id = http_resp
|
76
|
+
resp.http_headers = Headers.from_net_http(http_resp)
|
77
|
+
resp.http_status = http_resp.code.to_i
|
78
|
+
resp.request_id = http_resp["request-id"]
|
47
79
|
resp
|
48
80
|
end
|
49
81
|
end
|
data/lib/stripe/util.rb
CHANGED
@@ -24,97 +24,27 @@ module Stripe
|
|
24
24
|
OPTS_USER_SPECIFIED + Set[:client] - Set[:idempotency_key]
|
25
25
|
).freeze
|
26
26
|
|
27
|
-
def self.objects_to_ids(
|
28
|
-
case
|
27
|
+
def self.objects_to_ids(obj)
|
28
|
+
case obj
|
29
29
|
when APIResource
|
30
|
-
|
30
|
+
obj.id
|
31
31
|
when Hash
|
32
32
|
res = {}
|
33
|
-
|
33
|
+
obj.each { |k, v| res[k] = objects_to_ids(v) unless v.nil? }
|
34
34
|
res
|
35
35
|
when Array
|
36
|
-
|
36
|
+
obj.map { |v| objects_to_ids(v) }
|
37
37
|
else
|
38
|
-
|
38
|
+
obj
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
def self.object_classes
|
43
|
-
@object_classes ||=
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
Account::OBJECT_NAME => Account,
|
49
|
-
AccountLink::OBJECT_NAME => AccountLink,
|
50
|
-
AlipayAccount::OBJECT_NAME => AlipayAccount,
|
51
|
-
ApplePayDomain::OBJECT_NAME => ApplePayDomain,
|
52
|
-
ApplicationFee::OBJECT_NAME => ApplicationFee,
|
53
|
-
ApplicationFeeRefund::OBJECT_NAME => ApplicationFeeRefund,
|
54
|
-
Balance::OBJECT_NAME => Balance,
|
55
|
-
BalanceTransaction::OBJECT_NAME => BalanceTransaction,
|
56
|
-
BankAccount::OBJECT_NAME => BankAccount,
|
57
|
-
BitcoinReceiver::OBJECT_NAME => BitcoinReceiver,
|
58
|
-
BitcoinTransaction::OBJECT_NAME => BitcoinTransaction,
|
59
|
-
Card::OBJECT_NAME => Card,
|
60
|
-
Charge::OBJECT_NAME => Charge,
|
61
|
-
Checkout::Session::OBJECT_NAME => Checkout::Session,
|
62
|
-
CountrySpec::OBJECT_NAME => CountrySpec,
|
63
|
-
Coupon::OBJECT_NAME => Coupon,
|
64
|
-
Customer::OBJECT_NAME => Customer,
|
65
|
-
Dispute::OBJECT_NAME => Dispute,
|
66
|
-
EphemeralKey::OBJECT_NAME => EphemeralKey,
|
67
|
-
Event::OBJECT_NAME => Event,
|
68
|
-
ExchangeRate::OBJECT_NAME => ExchangeRate,
|
69
|
-
File::OBJECT_NAME => File,
|
70
|
-
File::OBJECT_NAME_ALT => File,
|
71
|
-
FileLink::OBJECT_NAME => FileLink,
|
72
|
-
Invoice::OBJECT_NAME => Invoice,
|
73
|
-
InvoiceItem::OBJECT_NAME => InvoiceItem,
|
74
|
-
InvoiceLineItem::OBJECT_NAME => InvoiceLineItem,
|
75
|
-
IssuerFraudRecord::OBJECT_NAME => IssuerFraudRecord,
|
76
|
-
Issuing::Authorization::OBJECT_NAME => Issuing::Authorization,
|
77
|
-
Issuing::Card::OBJECT_NAME => Issuing::Card,
|
78
|
-
Issuing::CardDetails::OBJECT_NAME => Issuing::CardDetails,
|
79
|
-
Issuing::Cardholder::OBJECT_NAME => Issuing::Cardholder,
|
80
|
-
Issuing::Dispute::OBJECT_NAME => Issuing::Dispute,
|
81
|
-
Issuing::Transaction::OBJECT_NAME => Issuing::Transaction,
|
82
|
-
LoginLink::OBJECT_NAME => LoginLink,
|
83
|
-
Order::OBJECT_NAME => Order,
|
84
|
-
OrderReturn::OBJECT_NAME => OrderReturn,
|
85
|
-
PaymentIntent::OBJECT_NAME => PaymentIntent,
|
86
|
-
Payout::OBJECT_NAME => Payout,
|
87
|
-
Person::OBJECT_NAME => Person,
|
88
|
-
Plan::OBJECT_NAME => Plan,
|
89
|
-
Product::OBJECT_NAME => Product,
|
90
|
-
Radar::ValueList::OBJECT_NAME => Radar::ValueList,
|
91
|
-
Radar::ValueListItem::OBJECT_NAME => Radar::ValueListItem,
|
92
|
-
Recipient::OBJECT_NAME => Recipient,
|
93
|
-
RecipientTransfer::OBJECT_NAME => RecipientTransfer,
|
94
|
-
Refund::OBJECT_NAME => Refund,
|
95
|
-
Reporting::ReportRun::OBJECT_NAME => Reporting::ReportRun,
|
96
|
-
Reporting::ReportType::OBJECT_NAME => Reporting::ReportType,
|
97
|
-
Reversal::OBJECT_NAME => Reversal,
|
98
|
-
Review::OBJECT_NAME => Review,
|
99
|
-
SKU::OBJECT_NAME => SKU,
|
100
|
-
Sigma::ScheduledQueryRun::OBJECT_NAME => Sigma::ScheduledQueryRun,
|
101
|
-
Source::OBJECT_NAME => Source,
|
102
|
-
SourceTransaction::OBJECT_NAME => SourceTransaction,
|
103
|
-
Subscription::OBJECT_NAME => Subscription,
|
104
|
-
SubscriptionItem::OBJECT_NAME => SubscriptionItem,
|
105
|
-
SubscriptionSchedule::OBJECT_NAME => SubscriptionSchedule,
|
106
|
-
SubscriptionScheduleRevision::OBJECT_NAME => SubscriptionScheduleRevision,
|
107
|
-
Terminal::ConnectionToken::OBJECT_NAME => Terminal::ConnectionToken,
|
108
|
-
Terminal::Location::OBJECT_NAME => Terminal::Location,
|
109
|
-
Terminal::Reader::OBJECT_NAME => Terminal::Reader,
|
110
|
-
ThreeDSecure::OBJECT_NAME => ThreeDSecure,
|
111
|
-
Token::OBJECT_NAME => Token,
|
112
|
-
Topup::OBJECT_NAME => Topup,
|
113
|
-
Transfer::OBJECT_NAME => Transfer,
|
114
|
-
UsageRecord::OBJECT_NAME => UsageRecord,
|
115
|
-
UsageRecordSummary::OBJECT_NAME => UsageRecordSummary,
|
116
|
-
WebhookEndpoint::OBJECT_NAME => WebhookEndpoint,
|
117
|
-
}
|
42
|
+
def self.object_classes
|
43
|
+
@object_classes ||= Stripe::ObjectTypes.object_names_to_classes
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.object_name_matches_class?(object_name, klass)
|
47
|
+
Util.object_classes[object_name] == klass
|
118
48
|
end
|
119
49
|
|
120
50
|
# Converts a hash of fields or an array of hashes into a +StripeObject+ or
|
@@ -130,12 +60,16 @@ module Stripe
|
|
130
60
|
# * +opts+ - Options for +StripeObject+ like an API key that will be reused
|
131
61
|
# on subsequent API calls.
|
132
62
|
def self.convert_to_stripe_object(data, opts = {})
|
63
|
+
opts = normalize_opts(opts)
|
64
|
+
|
133
65
|
case data
|
134
66
|
when Array
|
135
67
|
data.map { |i| convert_to_stripe_object(i, opts) }
|
136
68
|
when Hash
|
137
|
-
# Try converting to a known object class. If none available, fall back
|
138
|
-
|
69
|
+
# Try converting to a known object class. If none available, fall back
|
70
|
+
# to generic StripeObject
|
71
|
+
object_classes.fetch(data[:object], StripeObject)
|
72
|
+
.construct_from(data, opts)
|
139
73
|
else
|
140
74
|
data
|
141
75
|
end
|
@@ -144,24 +78,24 @@ module Stripe
|
|
144
78
|
def self.log_error(message, data = {})
|
145
79
|
if !Stripe.logger.nil? ||
|
146
80
|
!Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_ERROR
|
147
|
-
log_internal(message, data, color: :cyan,
|
148
|
-
|
81
|
+
log_internal(message, data, color: :cyan, level: Stripe::LEVEL_ERROR,
|
82
|
+
logger: Stripe.logger, out: $stderr)
|
149
83
|
end
|
150
84
|
end
|
151
85
|
|
152
86
|
def self.log_info(message, data = {})
|
153
87
|
if !Stripe.logger.nil? ||
|
154
88
|
!Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_INFO
|
155
|
-
log_internal(message, data, color: :cyan,
|
156
|
-
|
89
|
+
log_internal(message, data, color: :cyan, level: Stripe::LEVEL_INFO,
|
90
|
+
logger: Stripe.logger, out: $stdout)
|
157
91
|
end
|
158
92
|
end
|
159
93
|
|
160
94
|
def self.log_debug(message, data = {})
|
161
95
|
if !Stripe.logger.nil? ||
|
162
96
|
!Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_DEBUG
|
163
|
-
log_internal(message, data, color: :blue,
|
164
|
-
|
97
|
+
log_internal(message, data, color: :blue, level: Stripe::LEVEL_DEBUG,
|
98
|
+
logger: Stripe.logger, out: $stdout)
|
165
99
|
end
|
166
100
|
end
|
167
101
|
|
@@ -264,11 +198,13 @@ module Stripe
|
|
264
198
|
|
265
199
|
def self.check_string_argument!(key)
|
266
200
|
raise TypeError, "argument must be a string" unless key.is_a?(String)
|
201
|
+
|
267
202
|
key
|
268
203
|
end
|
269
204
|
|
270
205
|
def self.check_api_key!(key)
|
271
206
|
raise TypeError, "api_key must be a string" unless key.is_a?(String)
|
207
|
+
|
272
208
|
key
|
273
209
|
end
|
274
210
|
|
@@ -296,13 +232,13 @@ module Stripe
|
|
296
232
|
|
297
233
|
# Constant time string comparison to prevent timing attacks
|
298
234
|
# Code borrowed from ActiveSupport
|
299
|
-
def self.secure_compare(
|
300
|
-
return false unless
|
235
|
+
def self.secure_compare(str_a, str_b)
|
236
|
+
return false unless str_a.bytesize == str_b.bytesize
|
301
237
|
|
302
|
-
l =
|
238
|
+
l = str_a.unpack "C#{str_a.bytesize}"
|
303
239
|
|
304
240
|
res = 0
|
305
|
-
|
241
|
+
str_b.each_byte { |byte| res |= byte ^ l.shift }
|
306
242
|
res.zero?
|
307
243
|
end
|
308
244
|
|
@@ -311,14 +247,14 @@ module Stripe
|
|
311
247
|
#
|
312
248
|
|
313
249
|
COLOR_CODES = {
|
314
|
-
black:
|
315
|
-
red:
|
316
|
-
green:
|
317
|
-
yellow:
|
318
|
-
blue:
|
250
|
+
black: 0, light_black: 60,
|
251
|
+
red: 1, light_red: 61,
|
252
|
+
green: 2, light_green: 62,
|
253
|
+
yellow: 3, light_yellow: 63,
|
254
|
+
blue: 4, light_blue: 64,
|
319
255
|
magenta: 5, light_magenta: 65,
|
320
|
-
cyan:
|
321
|
-
white:
|
256
|
+
cyan: 6, light_cyan: 66,
|
257
|
+
white: 7, light_white: 67,
|
322
258
|
default: 9,
|
323
259
|
}.freeze
|
324
260
|
private_constant :COLOR_CODES
|
@@ -347,23 +283,32 @@ module Stripe
|
|
347
283
|
end
|
348
284
|
private_class_method :level_name
|
349
285
|
|
350
|
-
|
351
|
-
# 2.0.
|
352
|
-
def self.log_internal(message, data = {}, color: nil, level: nil, logger: nil, out: nil)
|
286
|
+
def self.log_internal(message, data = {}, color:, level:, logger:, out:)
|
353
287
|
data_str = data.reject { |_k, v| v.nil? }
|
354
288
|
.map do |(k, v)|
|
355
|
-
format("
|
289
|
+
format("%<key>s=%<value>s",
|
290
|
+
key: colorize(k, color, logger.nil? && !out.nil? && out.isatty),
|
291
|
+
value: wrap_logfmt_value(v))
|
356
292
|
end.join(" ")
|
357
293
|
|
358
294
|
if !logger.nil?
|
359
295
|
# the library's log levels are mapped to the same values as the
|
360
296
|
# standard library's logger
|
361
297
|
logger.log(level,
|
362
|
-
format("message
|
298
|
+
format("message=%<message>s %<data_str>s",
|
299
|
+
message: wrap_logfmt_value(message),
|
300
|
+
data_str: data_str))
|
363
301
|
elsif out.isatty
|
364
|
-
out.puts format("
|
302
|
+
out.puts format("%<level>s %<message>s %<data_str>s",
|
303
|
+
level: colorize(level_name(level)[0, 4].upcase,
|
304
|
+
color, out.isatty),
|
305
|
+
message: message,
|
306
|
+
data_str: data_str)
|
365
307
|
else
|
366
|
-
out.puts format("message
|
308
|
+
out.puts format("message=%<message>s level=%<level>s %<data_str>s",
|
309
|
+
message: wrap_logfmt_value(message),
|
310
|
+
level: level_name(level),
|
311
|
+
data_str: data_str)
|
367
312
|
end
|
368
313
|
end
|
369
314
|
private_class_method :log_internal
|
@@ -381,7 +326,7 @@ module Stripe
|
|
381
326
|
if %r{[^\w\-/]} =~ val
|
382
327
|
# If the string contains any special characters, escape any double
|
383
328
|
# quotes it has, remove newlines, and wrap the whole thing in quotes.
|
384
|
-
format(%("
|
329
|
+
format(%("%<value>s"), value: val.gsub('"', '\"').delete("\n"))
|
385
330
|
else
|
386
331
|
# Otherwise use the basic value if it looks like a standard set of
|
387
332
|
# characters (and allow a few special characters like hyphens, and
|