From 7b0125641f89e6d155537d1754adbcf4f6b91bea Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 21 Dec 2023 11:14:03 -0800 Subject: [PATCH 1/4] Add support for updatable singleton resources --- lib/stripe.rb | 1 + lib/stripe/api_operations/singleton_save.rb | 87 +++++++++++++++++++++ test/stripe/api_resource_test.rb | 55 +++++++++++++ test/stripe/generated_examples_test.rb | 24 ++++++ 4 files changed, 167 insertions(+) create mode 100644 lib/stripe/api_operations/singleton_save.rb diff --git a/lib/stripe.rb b/lib/stripe.rb index 890c4a9bc..13e060bf7 100644 --- a/lib/stripe.rb +++ b/lib/stripe.rb @@ -25,6 +25,7 @@ require "stripe/api_operations/nested_resource" require "stripe/api_operations/request" require "stripe/api_operations/save" +require "stripe/api_operations/singleton_save" require "stripe/api_operations/search" # API resource support classes diff --git a/lib/stripe/api_operations/singleton_save.rb b/lib/stripe/api_operations/singleton_save.rb new file mode 100644 index 000000000..c814c3e52 --- /dev/null +++ b/lib/stripe/api_operations/singleton_save.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module Stripe + module APIOperations + module SingletonSave + module ClassMethods + + # Updates an API resource + # + # Updates the identified resource with the passed in parameters. + # + # ==== Attributes + # + # * +params+ - A hash of parameters to pass to the API + # * +opts+ - A Hash of additional options (separate from the params / + # object values) to be added to the request. E.g. to allow for an + # idempotency_key to be passed in the request headers, or for the + # api_key to be overwritten. See + # {APIOperations::Request.execute_resource_request}. + def update(params = {}, opts = {}) + params.each_key do |k| + raise ArgumentError, "Cannot update protected field: #{k}" if protected_fields.include?(k) + end + + request_stripe_object( + method: :post, + path: resource_url, + params: params, + opts: opts + ) + end + end + + # The `save` method is DEPRECATED and will be removed in a future major + # version of the library. Use the `update` method on the resource instead. + # + # Creates or updates an API resource. + # + # If the resource doesn't yet have an assigned ID and the resource is one + # that can be created, then the method attempts to create the resource. + # The resource is updated otherwise. + # + # ==== Attributes + # + # * +params+ - Overrides any parameters in the resource's serialized data + # and includes them in the create or update. If +:req_url:+ is included + # in the list, it overrides the update URL used for the create or + # update. + # * +opts+ - A Hash of additional options (separate from the params / + # object values) to be added to the request. E.g. to allow for an + # idempotency_key to be passed in the request headers, or for the + # api_key to be overwritten. See + # {APIOperations::Request.execute_resource_request}. + def save(params = {}, opts = {}) + # We started unintentionally (sort of) allowing attributes sent to + # +save+ to override values used during the update. So as not to break + # the API, this makes that official here. + update_attributes(params) + + # Now remove any parameters that look like object attributes. + params = params.reject { |k, _| respond_to?(k) } + + values = serialize_params(self).merge(params) + + resp, opts = execute_resource_request(:post, resource_url, values, opts, ["save"]) + initialize_from(resp.data, opts) + end + extend Gem::Deprecate + deprecate :save, "the `update` class method (for examples " \ + "see https://github.com/stripe/stripe-ruby" \ + "/wiki/Migration-guide-for-v8)", 2022, 11 + + def self.included(base) + # Set `metadata` as additive so that when it's set directly we remember + # to clear keys that may have been previously set by sending empty + # values for them. + # + # It's possible that not every object with `Save` has `metadata`, but + # it's a close enough heuristic, and having this option set when there + # is no `metadata` field is not harmful. + base.additive_object_param(:metadata) + + base.extend(ClassMethods) + end + end + end +end diff --git a/test/stripe/api_resource_test.rb b/test/stripe/api_resource_test.rb index a0b3a98fe..4d2a2393e 100644 --- a/test/stripe/api_resource_test.rb +++ b/test/stripe/api_resource_test.rb @@ -782,6 +782,61 @@ def say_hello(params = {}, opts = {}) end end + context "singleton resource" do + + class TestSingletonResource < SingletonAPIResource # rubocop:todo Lint/ConstantDefinitionInBlock + include Stripe::APIOperations::SingletonSave + OBJECT_NAME = "test.singleton" + end + + + setup do + Util.instance_variable_set( + :@object_classes, + Stripe::ObjectTypes.object_names_to_classes.merge( + "test.singleton" => TestSingletonResource + ) + ) + end + teardown do + Util.class.instance_variable_set(:@object_classes, Stripe::ObjectTypes.object_names_to_classes) + end + + should "be retrievable" do + stub_request(:get, "#{Stripe.api_base}/v1/test/singleton") + .with(query: { foo: "bar" }, headers: { "Stripe-Account" => "acct_hi" }) + .to_return(body: JSON.generate({ object: "test.singleton", result: "hi!" })) + + settings = TestSingletonResource.retrieve({ foo: "bar" }, { stripe_account: "acct_hi" }) + assert settings.is_a? TestSingletonResource + assert_equal "hi!", settings.result + end + + should "be updatable" do + stub_request(:post, "#{Stripe.api_base}/v1/test/singleton") + .with(body: { foo: "bar" }, headers: { "Stripe-Account" => "acct_hi" }) + .to_return(body: JSON.generate({ object: "test.singleton", result: "hi!" })) + + settings = TestSingletonResource.update({ foo: "bar" }, { stripe_account: "acct_hi" }) + assert settings.is_a? TestSingletonResource + assert_equal "hi!", settings.result + end + + should "be saveable" do + stub_request(:get, "#{Stripe.api_base}/v1/test/singleton") + .to_return(body: JSON.generate({ object: "test.singleton", result: "hi!" })) + + stub_request(:post, "#{Stripe.api_base}/v1/test/singleton") + .with(body: { result: "hello" }) + .to_return(body: JSON.generate({ object: "test.singleton", result: "hello" })) + + settings = TestSingletonResource.retrieve + settings.result = "hello" + settings.save + assert_requested :post, "#{Stripe.api_base}/v1/test/singleton", times: 1 + end + end + @@fixtures = {} # rubocop:disable Style/ClassVars setup do if @@fixtures.empty? diff --git a/test/stripe/generated_examples_test.rb b/test/stripe/generated_examples_test.rb index 457aef51c..0de97c761 100644 --- a/test/stripe/generated_examples_test.rb +++ b/test/stripe/generated_examples_test.rb @@ -1571,6 +1571,30 @@ class CodegennedExampleTest < Test::Unit::TestCase Stripe::TaxRate.update("txr_xxxxxxxxxxxxx", { active: false }) assert_requested :post, "#{Stripe.api_base}/v1/tax_rates/txr_xxxxxxxxxxxxx" end + should "Test tax registrations get" do + Stripe::Tax::Registration.list({ status: "all" }) + assert_requested :get, "#{Stripe.api_base}/v1/tax/registrations?status=all" + end + should "Test tax registrations post" do + Stripe::Tax::Registration.create({ + country: "IE", + country_options: { ie: { type: "oss_union" } }, + active_from: "now", + }) + assert_requested :post, "#{Stripe.api_base}/v1/tax/registrations" + end + should "Test tax registrations post 2" do + Stripe::Tax::Registration.update("taxreg_xxxxxxxxxxxxx", { expires_at: "now" }) + assert_requested :post, "#{Stripe.api_base}/v1/tax/registrations/taxreg_xxxxxxxxxxxxx" + end + should "Test tax settings get" do + Stripe::Tax::Settings.retrieve + assert_requested :get, "#{Stripe.api_base}/v1/tax/settings?" + end + should "Test tax settings post" do + Stripe::Tax::Settings.update({ defaults: { tax_code: "txcd_10000000" } }) + assert_requested :post, "#{Stripe.api_base}/v1/tax/settings" + end should "Test tax transactions create from calculation post" do Stripe::Tax::Transaction.create_from_calculation({ calculation: "xxx", From 5546b76d9aa5710a706abc19388d06c5d9914376 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 21 Dec 2023 11:18:42 -0800 Subject: [PATCH 2/4] codegen --- lib/stripe/api_operations/singleton_save.rb | 5 ++--- lib/stripe/resources/tax/settings.rb | 2 +- test/stripe/api_resource_test.rb | 2 -- test/stripe/generated_examples_test.rb | 16 ---------------- 4 files changed, 3 insertions(+), 22 deletions(-) diff --git a/lib/stripe/api_operations/singleton_save.rb b/lib/stripe/api_operations/singleton_save.rb index c814c3e52..ec9b5a2b4 100644 --- a/lib/stripe/api_operations/singleton_save.rb +++ b/lib/stripe/api_operations/singleton_save.rb @@ -4,7 +4,6 @@ module Stripe module APIOperations module SingletonSave module ClassMethods - # Updates an API resource # # Updates the identified resource with the passed in parameters. @@ -67,8 +66,8 @@ def save(params = {}, opts = {}) end extend Gem::Deprecate deprecate :save, "the `update` class method (for examples " \ - "see https://github.com/stripe/stripe-ruby" \ - "/wiki/Migration-guide-for-v8)", 2022, 11 + "see https://github.com/stripe/stripe-ruby" \ + "/wiki/Migration-guide-for-v8)", 2022, 11 def self.included(base) # Set `metadata` as additive so that when it's set directly we remember diff --git a/lib/stripe/resources/tax/settings.rb b/lib/stripe/resources/tax/settings.rb index 6a177a0a6..2a4e25531 100644 --- a/lib/stripe/resources/tax/settings.rb +++ b/lib/stripe/resources/tax/settings.rb @@ -7,7 +7,7 @@ module Tax # # Related guide: [Using the Settings API](https://stripe.com/docs/tax/settings-api) class Settings < SingletonAPIResource - include Stripe::APIOperations::Save + include Stripe::APIOperations::SingletonSave OBJECT_NAME = "tax.settings" end diff --git a/test/stripe/api_resource_test.rb b/test/stripe/api_resource_test.rb index 4d2a2393e..d4e6a4806 100644 --- a/test/stripe/api_resource_test.rb +++ b/test/stripe/api_resource_test.rb @@ -783,13 +783,11 @@ def say_hello(params = {}, opts = {}) end context "singleton resource" do - class TestSingletonResource < SingletonAPIResource # rubocop:todo Lint/ConstantDefinitionInBlock include Stripe::APIOperations::SingletonSave OBJECT_NAME = "test.singleton" end - setup do Util.instance_variable_set( :@object_classes, diff --git a/test/stripe/generated_examples_test.rb b/test/stripe/generated_examples_test.rb index 0de97c761..96a9516e2 100644 --- a/test/stripe/generated_examples_test.rb +++ b/test/stripe/generated_examples_test.rb @@ -1571,22 +1571,6 @@ class CodegennedExampleTest < Test::Unit::TestCase Stripe::TaxRate.update("txr_xxxxxxxxxxxxx", { active: false }) assert_requested :post, "#{Stripe.api_base}/v1/tax_rates/txr_xxxxxxxxxxxxx" end - should "Test tax registrations get" do - Stripe::Tax::Registration.list({ status: "all" }) - assert_requested :get, "#{Stripe.api_base}/v1/tax/registrations?status=all" - end - should "Test tax registrations post" do - Stripe::Tax::Registration.create({ - country: "IE", - country_options: { ie: { type: "oss_union" } }, - active_from: "now", - }) - assert_requested :post, "#{Stripe.api_base}/v1/tax/registrations" - end - should "Test tax registrations post 2" do - Stripe::Tax::Registration.update("taxreg_xxxxxxxxxxxxx", { expires_at: "now" }) - assert_requested :post, "#{Stripe.api_base}/v1/tax/registrations/taxreg_xxxxxxxxxxxxx" - end should "Test tax settings get" do Stripe::Tax::Settings.retrieve assert_requested :get, "#{Stripe.api_base}/v1/tax/settings?" From bb70dc0194840553ef2702fabf8bd136f27aabfb Mon Sep 17 00:00:00 2001 From: pakrym-stripe <99349468+pakrym-stripe@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:32:40 -0800 Subject: [PATCH 3/4] Update lib/stripe/api_operations/singleton_save.rb Co-authored-by: anniel-stripe <97691964+anniel-stripe@users.noreply.github.com> --- lib/stripe/api_operations/singleton_save.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stripe/api_operations/singleton_save.rb b/lib/stripe/api_operations/singleton_save.rb index ec9b5a2b4..e5f99b109 100644 --- a/lib/stripe/api_operations/singleton_save.rb +++ b/lib/stripe/api_operations/singleton_save.rb @@ -4,7 +4,7 @@ module Stripe module APIOperations module SingletonSave module ClassMethods - # Updates an API resource + # Updates a singleton API resource # # Updates the identified resource with the passed in parameters. # From bd0d2f8d2178de2f698c22f2659310a90c93e195 Mon Sep 17 00:00:00 2001 From: pakrym-stripe <99349468+pakrym-stripe@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:32:45 -0800 Subject: [PATCH 4/4] Update lib/stripe/api_operations/singleton_save.rb Co-authored-by: anniel-stripe <97691964+anniel-stripe@users.noreply.github.com> --- lib/stripe/api_operations/singleton_save.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stripe/api_operations/singleton_save.rb b/lib/stripe/api_operations/singleton_save.rb index e5f99b109..d1e367cd0 100644 --- a/lib/stripe/api_operations/singleton_save.rb +++ b/lib/stripe/api_operations/singleton_save.rb @@ -33,7 +33,7 @@ def update(params = {}, opts = {}) # The `save` method is DEPRECATED and will be removed in a future major # version of the library. Use the `update` method on the resource instead. # - # Creates or updates an API resource. + # Updates a singleton API resource. # # If the resource doesn't yet have an assigned ID and the resource is one # that can be created, then the method attempts to create the resource.