defmodule Stripe.Subscription do
@moduledoc """
Work with Stripe subscription objects.
You can:
- Create a subscription
- Retrieve a subscription
- Update a subscription
- Delete a subscription
- Search subscriptions
Stripe API reference: https://stripe.com/docs/api#subscription
"""
use Stripe.Entity
import Stripe.Request
@type pause_collection :: %{
behavior: String.t(),
resumes_at: Stripe.timestamp()
}
@type pending_invoice_item_interval :: %{
interval: String.t(),
interval_count: integer
}
@type pending_update :: %{
billing_cycle_anchor: Stripe.timestamp(),
expires_at: Stripe.timestamp(),
subscription_items: [Stripe.SubscriptionItem.t()],
trial_end: Stripe.timestamp(),
trial_from_plan: boolean
}
@type t :: %__MODULE__{
id: Stripe.id(),
object: String.t(),
application_fee_percent: float | nil,
automatic_tax: map,
billing_cycle_anchor: Stripe.timestamp() | nil,
billing_thresholds: map | nil,
collection_method: String.t() | nil,
collection_method_cycle_anchor: Stripe.timestamp() | nil,
collection_method_thresholds: Stripe.Types.collection_method_thresholds() | nil,
cancel_at: Stripe.timestamp() | nil,
cancel_at_period_end: boolean,
canceled_at: Stripe.timestamp() | nil,
created: Stripe.timestamp(),
currency: String.t() | nil,
current_period_end: Stripe.timestamp() | nil,
current_period_start: Stripe.timestamp() | nil,
customer: Stripe.id() | Stripe.Customer.t(),
days_until_due: integer | nil,
default_payment_method: Stripe.id() | Stripe.PaymentMethod.t() | nil,
default_source: Stripe.id() | Stripe.Source.t() | nil,
default_tax_rates: list(Stripe.TaxRate),
discount: Stripe.Discount.t() | nil,
ended_at: Stripe.timestamp() | nil,
items: Stripe.List.t(Stripe.SubscriptionItem.t()),
latest_invoice: Stripe.id() | Stripe.Invoice.t() | nil,
livemode: boolean,
metadata: Stripe.Types.metadata(),
next_pending_invoice_item_invoice: Stripe.timestamp() | nil,
pending_invoice_item_interval: pending_invoice_item_interval() | nil,
pending_setup_intent: Stripe.SetupIntent.t() | nil,
pending_update: pending_update() | nil,
plan: Stripe.Plan.t() | nil,
pause_collection: pause_collection() | nil,
promotion_code: pause_collection() | nil,
quantity: integer | nil,
schedule: String.t() | nil,
start_date: Stripe.timestamp(),
status: String.t(),
transfer_data: map,
trial_end: Stripe.timestamp() | nil,
trial_start: Stripe.timestamp() | nil
}
defstruct [
:id,
:object,
:application_fee_percent,
:automatic_tax,
:billing_cycle_anchor,
:billing_thresholds,
:collection_method,
:collection_method_cycle_anchor,
:collection_method_thresholds,
:cancel_at,
:cancel_at_period_end,
:canceled_at,
:currency,
:created,
:current_period_end,
:current_period_start,
:customer,
:days_until_due,
:default_payment_method,
:default_source,
:default_tax_rates,
:discount,
:ended_at,
:items,
:latest_invoice,
:livemode,
:metadata,
:next_pending_invoice_item_invoice,
:pending_invoice_item_interval,
:pending_setup_intent,
:pending_update,
:plan,
:pause_collection,
:promotion_code,
:quantity,
:schedule,
:start_date,
:status,
:tax_rate,
:test_clock,
:transfer_data,
:trial_end,
:trial_start
]
@plural_endpoint "subscriptions"
@doc """
Create a subscription.
"""
@spec create(params, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
when params: %{
:customer => Stripe.id() | Stripe.Customer.t(),
optional(:application_fee_percent) => integer,
optional(:billing_cycle_anchor) => Stripe.timestamp(),
optional(:billing_thresholds) => map,
optional(:collection_method) => String.t(),
optional(:collection_method_cycle_anchor) => Stripe.timestamp(),
optional(:cancel_at) => Stripe.timestamp(),
optional(:cancel_at_period_end) => boolean,
optional(:collection_method) => String.t(),
optional(:coupon) => Stripe.id() | Stripe.Coupon.t(),
optional(:days_until_due) => non_neg_integer,
:items => [
%{
optional(:plan) => Stripe.id() | Stripe.Plan.t(),
optional(:price) => Stripe.id() | Stripe.Price.t(),
optional(:billing_methods) => map,
optional(:metadata) => map,
optional(:quantity) => non_neg_integer,
optional(:tax_rates) => list
}
],
optional(:default_payment_method) => Stripe.id(),
optional(:default_tax_rates) => [Stripe.id()],
optional(:expand) => [String.t()],
optional(:metadata) => Stripe.Types.metadata(),
optional(:payment_behavior) => String.t(),
optional(:prorate) => boolean,
optional(:proration_behavior) => String.t(),
optional(:promotion_code) => Stripe.id(),
optional(:tax_rate) => Stripe.id() | Stripe.TaxRate.t(),
optional(:trial_end) => Stripe.timestamp() | :now,
optional(:trial_from_plan) => boolean,
optional(:trial_period_days) => non_neg_integer
}
def create(params, opts \\ []) do
new_request(opts)
|> put_endpoint(@plural_endpoint)
|> put_params(params)
|> put_method(:post)
|> cast_to_id([:coupon, :customer])
|> make_request()
end
@doc """
Retrieve a subscription.
"""
@spec retrieve(Stripe.id() | t, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
def retrieve(id, opts \\ []) do
new_request(opts)
|> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}")
|> put_method(:get)
|> make_request()
end
@doc """
Update a subscription.
Takes the `id` and a map of changes.
"""
@spec update(Stripe.id() | t, params, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
when params: %{
optional(:application_fee_percent) => float,
optional(:billing_cycle_anchor) => Stripe.timestamp(),
optional(:billing_thresholds) => map,
optional(:collection_method) => String.t(),
optional(:collection_method_cycle_anchor) => Stripe.timestamp(),
optional(:cancel_at) => Stripe.timestamp(),
optional(:cancel_at_period_end) => boolean(),
optional(:collection_method) => String.t(),
optional(:coupon) => Stripe.id() | Stripe.Coupon.t(),
optional(:days_until_due) => non_neg_integer,
optional(:items) => [
%{
optional(:id) => Stripe.id() | binary(),
optional(:plan) => Stripe.id() | Stripe.Plan.t(),
optional(:price) => Stripe.id() | Stripe.Price.t(),
optional(:billing_methods) => map,
optional(:metadata) => map,
optional(:quantity) => non_neg_integer,
optional(:tax_rates) => list
}
],
optional(:default_payment_method) => Stripe.id(),
optional(:default_tax_rates) => [Stripe.id()],
optional(:metadata) => Stripe.Types.metadata(),
optional(:pause_collection) => pause_collection(),
optional(:prorate) => boolean,
optional(:proration_behavior) => String.t(),
optional(:proration_date) => Stripe.timestamp(),
optional(:tax_rate) => Stripe.id() | Stripe.TaxRate.t(),
optional(:trial_end) => Stripe.timestamp() | :now,
optional(:trial_from_plan) => boolean
}
def update(id, params, opts \\ []) do
new_request(opts)
|> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}")
|> put_method(:post)
|> put_params(params)
|> cast_to_id([:coupon])
|> make_request()
end
@doc """
Delete a subscription.
Takes the subscription `id` or a `Stripe.Subscription` struct.
"""
@spec delete(Stripe.id() | t) :: {:ok, t} | {:error, Stripe.Error.t()}
def delete(id), do: delete(id, %{}, [])
@doc """
Delete a subscription.
Takes the subscription `id` or a `Stripe.Subscription` struct.
Second argument can be a map of cancellation `params`, such as `invoice_now`,
or a list of options, such as custom API key.
"""
@spec delete(Stripe.id() | t, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
def delete(id, opts) when is_list(opts) do
delete(id, %{}, opts)
end
@spec delete(Stripe.id() | t, params) :: {:ok, t} | {:error, Stripe.Error.t()}
when params: %{
optional(:invoice_now) => boolean,
optional(:prorate) => boolean
}
def delete(id, params) when is_map(params) do
delete(id, params, [])
end
@doc """
Delete a subscription.
Takes the subscription `id` or a `Stripe.Subscription` struct.
Second argument is a map of cancellation `params`, such as `invoice_now`.
Third argument is a list of options, such as custom API key.
"""
@spec delete(Stripe.id() | t, params, Stripe.options()) ::
{:ok, t} | {:error, Stripe.Error.t()}
when params: %{
optional(:invoice_now) => boolean,
optional(:prorate) => boolean
}
def delete(id, params, opts) do
new_request(opts)
|> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}")
|> put_method(:delete)
|> put_params(params)
|> make_request()
end
@doc """
List all subscriptions.
"""
@spec list(params, Stripe.options()) :: {:ok, Stripe.List.t(t)} | {:error, Stripe.Error.t()}
when params: %{
optional(:collection_method) => String.t(),
optional(:created) => Stripe.date_query(),
optional(:customer) => Stripe.Customer.t() | Stripe.id(),
optional(:ending_before) => t | Stripe.id(),
optional(:limit) => 1..100,
optional(:plan) => Stripe.Plan.t() | Stripe.id(),
optional(:price) => Stripe.Price.t() | Stripe.id(),
optional(:starting_after) => t | Stripe.id(),
optional(:status) => String.t()
}
def list(params \\ %{}, opts \\ []) do
new_request(opts)
|> prefix_expansions()
|> put_endpoint(@plural_endpoint)
|> put_method(:get)
|> put_params(params)
|> cast_to_id([:customer, :ending_before, :plan, :price, :starting_after])
|> make_request()
end
@doc """
Search subscriptions
"""
@spec search(params, Stripe.options()) ::
{:ok, Stripe.SearchResult.t(t)} | {:error, Stripe.Error.t()}
when params: %{
:query => Stripe.search_query(),
optional(:limit) => 1..100,
optional(:page) => String.t()
}
def search(params, opts \\ []) do
new_request(opts)
|> prefix_expansions()
|> put_endpoint(@plural_endpoint <> "/search")
|> put_method(:get)
|> put_params(params)
|> make_request()
end
@doc """
Deletes the discount on a subscription.
"""
@spec delete_discount(Stripe.id() | t, Stripe.options()) ::
{:ok, t} | {:error, Stripe.Error.t()}
def delete_discount(id, opts \\ []) do
new_request(opts)
|> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}/discount")
|> put_method(:delete)
|> make_request()
end
end