From 6ffacea45fc11d0aa1414927202bdbfcb920a969 Mon Sep 17 00:00:00 2001 From: Dominic Charley-Roy <78050200+dcr-stripe@users.noreply.github.com> Date: Wed, 8 Jun 2022 11:55:12 -0400 Subject: [PATCH] fix: Update cash balance methods to no longer require nested ID. (#1063) --- lib/stripe/resources/customer.rb | 43 +++++++++++++-- test/stripe/customer_test.rb | 75 ++++++++++++++++++++++++++ test/stripe/generated_examples_test.rb | 16 ++++++ 3 files changed, 131 insertions(+), 3 deletions(-) diff --git a/lib/stripe/resources/customer.rb b/lib/stripe/resources/customer.rb index ef6122242..e57c85be3 100644 --- a/lib/stripe/resources/customer.rb +++ b/lib/stripe/resources/customer.rb @@ -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, @@ -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/%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/%s/cash_balance", { customer: CGI.escape(customer) }), + params, + opts + ) + Util.convert_to_stripe_object(resp.data, opts) + end end end diff --git a/test/stripe/customer_test.rb b/test/stripe/customer_test.rb index 20a80a115..90487a7e5 100644 --- a/test/stripe/customer_test.rb +++ b/test/stripe/customer_test.rb @@ -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 diff --git a/test/stripe/generated_examples_test.rb b/test/stripe/generated_examples_test.rb index 5bccc6243..fffc1872d 100644 --- a/test/stripe/generated_examples_test.rb +++ b/test/stripe/generated_examples_test.rb @@ -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")