Skip to content

Commit

Permalink
fix: Update cash balance methods to no longer require nested ID. (#1063)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcr-stripe authored Jun 8, 2022
1 parent df255e0 commit 6ffacea
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 3 deletions.
43 changes: 40 additions & 3 deletions lib/stripe/resources/customer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ class Customer < APIResource
custom_method :create_funding_instructions, http_verb: :post, http_path: "funding_instructions"
custom_method :list_payment_methods, http_verb: :get, http_path: "payment_methods"

nested_resource_class_methods :cash_balance,
operations: %i[retrieve update],
resource_plural: "cash_balance"
nested_resource_class_methods :balance_transaction,
operations: %i[create retrieve update list]
nested_resource_class_methods :tax_id,
Expand Down Expand Up @@ -94,5 +91,45 @@ def self.search(params = {}, opts = {})
def self.search_auto_paging_each(params = {}, opts = {}, &blk)
search(params, opts).auto_paging_each(&blk)
end

def self.retrieve_cash_balance(
customer,
opts_or_unused_nested_id = nil,
opts = {}
)
# Support two call patterns for backwards compatibility.
# 1. Legacy: (nil unused nested_id, opts)
# 2. Fixed pattern: (opts)
if !opts_or_unused_nested_id.nil? && opts_or_unused_nested_id.class == Hash && opts.empty?
opts = opts_or_unused_nested_id
end
resp, opts = execute_resource_request(
:get,
format("/v1/customers/%<customer>s/cash_balance", { customer: CGI.escape(customer) }),
{},
opts
)
Util.convert_to_stripe_object(resp.data, opts)
end

def self.update_cash_balance(
customer,
unused_nested_id = nil,
params = {},
opts = {}
)
# Do not allow passing in a hash as the second argument, as we require a nil for compatibility reasons. We cannot differentiate from a legacy pattern (nil, params) and a modern pattern (nil for params, opts).
if !unused_nested_id.nil? && unused_nested_id.class == Hash
raise ArgumentError, "update_cash_balance requires the second argument always be nil for legacy reasons."
end

resp, opts = execute_resource_request(
:post,
format("/v1/customers/%<customer>s/cash_balance", { customer: CGI.escape(customer) }),
params,
opts
)
Util.convert_to_stripe_object(resp.data, opts)
end
end
end
75 changes: 75 additions & 0 deletions test/stripe/customer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,5 +222,80 @@ class CustomerTest < Test::Unit::TestCase
assert sources.data.is_a?(Array)
end
end

context "cash_balance compatibility" do
# These tests are present for compatibility purposes. Previously the cash
# balance methods required nil as a second nested_id parameter. The method
# has been patched to no longer require this, but we want to preserve
# compatibility for existing users.

context "#retrieve_cash_balance" do
should "legacy call pattern - retrieve_cash_balance(customer_id, nil)" do
Stripe::Customer.retrieve_cash_balance("cus_123", nil)
assert_requested :get, "#{Stripe.api_base}/v1/customers/cus_123/cash_balance"
end

should "legacy call pattern - retrieve_cash_balance(customer_id, nil, opts)" do
# Assert that we're actually making a change by swapping out the API base.
assert Stripe.api_base != Stripe.connect_base

Stripe::Customer.retrieve_cash_balance("cus_123", nil, { api_base: Stripe.connect_base })
assert_requested :get, "#{Stripe.connect_base}/v1/customers/cus_123/cash_balance"
end

should "modern call pattern - retrieve_cash_balance(customer_id, opts)" do
# Assert that we're actually making a change by swapping out the API base.
assert Stripe.api_base != Stripe.connect_base

Stripe::Customer.retrieve_cash_balance("cus_123", { api_base: Stripe.connect_base })
assert_requested :get, "#{Stripe.connect_base}/v1/customers/cus_123/cash_balance"
end
end

context "#update_cash_balance" do
should "legacy call pattern - update_cash_balance(customer, nil, params)" do
Stripe::Customer.update_cash_balance("cus_123", nil, { settings: { reconciliation_mode: "manual" } })

assert_requested :post, "#{Stripe.api_base}/v1/customers/cus_123/cash_balance" do |req|
req.body == "settings[reconciliation_mode]=manual"
end
end

should "legacy call pattern - update_cash_balance(customer, nil, params, opts)" do
# Assert that we're actually making a change by swapping out the API base.
assert Stripe.api_base != Stripe.connect_base

Stripe::Customer.update_cash_balance(
"cus_123",
nil,
{ settings: { reconciliation_mode: "manual" } },
{ api_base: Stripe.connect_base }
)

assert_requested :post, "#{Stripe.connect_base}/v1/customers/cus_123/cash_balance" do |req|
req.body == "settings[reconciliation_mode]=manual"
end
end

should "modern call pattern - update_cash_balance(customer)" do
Stripe::Customer.update_cash_balance("cus_123")

assert_requested :post, "#{Stripe.api_base}/v1/customers/cus_123/cash_balance"
end

should "modern call pattern - fail if passing in hash to second argument" do
# We catch this on purpose to avoid mis-using the call as is.
# Unfortunately we can't automatically shift over arguments (eg.
# update_cash_balance(customer_id, params, opts) ->
# update_cash_balance(customer_id, nil, params, opts)) since we have
# the problematic case of update_cash_balance(customer_id, nil, hash)
# where we can't differentiate params and opts for the second hash.
e = assert_raises(ArgumentError) do
Stripe::Customer.update_cash_balance("cus_123", { settings: { reconciliation_mode: "manual" } })
end
assert_match("update_cash_balance requires the second argument always be nil", e.message)
end
end
end
end
end
16 changes: 16 additions & 0 deletions test/stripe/generated_examples_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,22 @@ class CodegennedExampleTest < Test::Unit::TestCase
assert_requested :post, "#{Stripe.api_base}/v1/accounts/acct_xxxxxxxxxxxxx/capabilities/card_payments"
end
end
context "CashBalance.retrieve" do
should "support requests with args: customer" do
Stripe::Customer.retrieve_cash_balance("cus_123")
assert_requested :get, "#{Stripe.api_base}/v1/customers/cus_123/cash_balance?"
end
end
context "CashBalance.update" do
should "support requests with args: customer, settings" do
Stripe::Customer.update_cash_balance(
"cus_123",
nil,
{ settings: { reconciliation_mode: "manual" } }
)
assert_requested :post, "#{Stripe.api_base}/v1/customers/cus_123/cash_balance"
end
end
context "Charge.capture" do
should "support requests with args: id" do
Stripe::Charge.capture("ch_xxxxxxxxxxxxx")
Expand Down

0 comments on commit 6ffacea

Please sign in to comment.