Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for updatable singleton resources #1304

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/stripe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
86 changes: 86 additions & 0 deletions lib/stripe/api_operations/singleton_save.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# frozen_string_literal: true

module Stripe
module APIOperations
module SingletonSave
module ClassMethods
# Updates an API resource
pakrym-stripe marked this conversation as resolved.
Show resolved Hide resolved
#
# 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.
pakrym-stripe marked this conversation as resolved.
Show resolved Hide resolved
#
# 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
2 changes: 1 addition & 1 deletion lib/stripe/resources/tax/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions test/stripe/api_resource_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,59 @@ 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?
Expand Down
8 changes: 8 additions & 0 deletions test/stripe/generated_examples_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,14 @@ 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 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",
Expand Down