defmodule Stripe.Invoice do @moduledoc """ Work with Stripe invoice objects. You can: - Create an invoice - Retrieve an invoice - Update an invoice - Void an invoice - Search invoices Does not take options yet. Stripe API reference: https://stripe.com/docs/api#invoice """ use Stripe.Entity import Stripe.Request @type t :: %__MODULE__{ id: Stripe.id(), object: String.t(), account_country: String.t(), account_name: String.t(), account_tax_ids: list(String.t()), amount_due: integer, amount_paid: integer, amount_remaining: integer, application_fee_amount: integer | nil, attempt_count: non_neg_integer, attempted: boolean, auto_advance: boolean, automatic_tax: map, billing_reason: String.t() | nil, charge: Stripe.id() | Stripe.Charge.t() | nil, collection_method: String.t() | nil, created: Stripe.timestamp(), currency: String.t(), custom_fields: custom_fields() | nil, customer: Stripe.id() | Stripe.Customer.t(), customer_address: Stripe.Types.address() | nil, customer_email: String.t() | nil, customer_name: String.t() | nil, customer_phone: String.t() | nil, customer_shipping: Stripe.Types.shipping() | nil, customer_tax_exempt: String.t() | nil, customer_tax_ids: Stripe.List.t(map) | nil, default_payment_method: String.t() | nil, default_source: String.t() | nil, default_tax_rates: Stripe.List.t(map) | nil, deleted: boolean | nil, description: String.t() | nil, discount: Stripe.Discount.t() | nil, discounts: list(String.t()), due_date: Stripe.timestamp() | nil, ending_balance: integer | nil, footer: String.t() | nil, hosted_invoice_url: String.t() | nil, invoice_pdf: String.t() | nil, last_finalization_error: map, lines: Stripe.List.t(Stripe.LineItem.t()), livemode: boolean, metadata: Stripe.Types.metadata() | nil, next_payment_attempt: Stripe.timestamp() | nil, number: String.t() | nil, on_behalf_of: String.t(), paid: boolean, payment_intent: String.t() | nil, payment_settings: map, period_end: Stripe.timestamp(), period_start: Stripe.timestamp(), post_payment_credit_notes_amount: integer, pre_payment_credit_notes_amount: integer, receipt_number: String.t() | nil, starting_balance: integer, statement_descriptor: String.t() | nil, status: String.t() | nil, status_transitions: status_transitions() | nil, subscription: Stripe.id() | Stripe.Subscription.t() | nil, subscription_proration_date: Stripe.timestamp() | nil, subtotal: integer, tax: integer | nil, tax_rate: Stripe.id() | Stripe.TaxRate.t() | nil, threshold_reason: nil | %{ amount_gte: integer, item_reasons: [ %{ line_item_ids: [String.t()], usage_gte: integer } ] }, total: integer, total_discount_amounts: Stripe.List.t(map) | nil, total_tax_amounts: Stripe.List.t(map) | nil, transfer_data: map, webhooks_delivered_at: Stripe.timestamp() | nil } @type custom_fields :: list(%{ name: String.t(), value: String.t() }) @type invoice_settings :: %{ optional(:default_payment_method) => String.t() | Stripe.PaymentMethod.t(), optional(:custom_fields) => custom_fields, optional(:footer) => String.t() } @type status_transitions :: list(%{ finalized_at: Stripe.timestamp() | nil, marked_uncollectible_at: Stripe.timestamp() | nil, paid_at: Stripe.timestamp() | nil, voided_at: Stripe.timestamp() | nil }) defstruct [ :id, :object, :account_country, :account_name, :account_tax_ids, :amount_due, :amount_paid, :amount_remaining, :application_fee_amount, :attempt_count, :attempted, :auto_advance, :automatic_tax, :billing_reason, :charge, :collection_method, :created, :currency, :custom_fields, :customer, :customer_address, :customer_email, :customer_name, :customer_phone, :customer_shipping, :customer_tax_exempt, :customer_tax_ids, :default_payment_method, :default_source, :default_tax_rates, :deleted, :description, :discount, :discounts, :due_date, :ending_balance, :footer, :hosted_invoice_url, :invoice_pdf, :last_finalization_error, :lines, :livemode, :metadata, :next_payment_attempt, :number, :on_behalf_of, :paid, :payment_intent, :payment_settings, :period_end, :period_start, :post_payment_credit_notes_amount, :pre_payment_credit_notes_amount, :receipt_number, :starting_balance, :statement_descriptor, :status, :status_transitions, :subscription, :subscription_proration_date, :subtotal, :tax, :tax_rate, :threshold_reason, :total, :total_discount_amounts, :total_tax_amounts, :transfer_data, :webhooks_delivered_at ] @plural_endpoint "invoices" @doc """ Create an invoice This endpoint creates a draft invoice for a given customer. The draft invoice created pulls in all pending invoice items on that customer, including prorations. See [Stripe docs](https://stripe.com/docs/api/invoices/update) """ @spec create(params, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()} when params: %{ optional(:account_tax_ids) => list(String.t()), optional(:application_fee_amount) => integer, optional(:auto_advance) => boolean, optional(:automatic_tax) => map, optional(:collection_method) => String.t(), :customer => Stripe.id() | Stripe.Customer.t(), optional(:custom_fields) => custom_fields, optional(:days_until_due) => integer, optional(:default_payment_method) => String.t(), optional(:default_source) => String.t(), optional(:default_tax_rates) => [Stripe.id()], optional(:description) => String.t(), optional(:discounts) => list(String.t()), optional(:due_date) => Stripe.timestamp(), optional(:footer) => String.t(), optional(:metadata) => Stripe.Types.metadata(), optional(:payment_settings) => map, optional(:statement_descriptor) => String.t(), optional(:subscription) => Stripe.id() | Stripe.Subscription.t() } | %{} def create(params, opts \\ []) do new_request(opts) |> put_endpoint(@plural_endpoint) |> put_params(params) |> put_method(:post) |> cast_to_id([:subscription]) |> make_request() end @doc """ Retrieve an invoice. Retrieves the invoice with the given ID. See [Stripe docs](https://stripe.com/docs/api/invoices/retrieve) """ @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 an invoice. Takes the `id` and a map of changes. Draft invoices are fully editable. Once an invoice is finalized, monetary values, as well as collection_method, become uneditable. See [Stripe docs](https://stripe.com/docs/api/invoices/update) """ @spec update(Stripe.id() | t, params, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()} when params: %{ optional(:account_tax_ids) => list(String.t()), optional(:application_fee_amount) => integer, optional(:auto_advance) => boolean, optional(:automatic_tax) => map, optional(:custom_fields) => custom_fields, optional(:days_until_due) => integer, optional(:default_payment_method) => String.t(), optional(:default_source) => String.t(), optional(:default_tax_rates) => [Stripe.id()], optional(:description) => String.t(), optional(:discounts) => list(String.t()), optional(:due_date) => Stripe.timestamp(), optional(:footer) => String.t(), optional(:forgiven) => boolean, optional(:metadata) => Stripe.Types.metadata(), optional(:paid) => boolean, optional(:payment_settings) => map, optional(:statement_descriptor) => String.t() } | %{} def update(id, params, opts \\ []) do new_request(opts) |> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}") |> put_method(:post) |> put_params(params) |> make_request() end @doc """ Retrieve an upcoming invoice At any time, you can preview the upcoming invoice for a customer. This will show you all the charges that are pending, including subscription renewal charges, invoice item charges, etc. It will also show you any discount that is applicable to the customer. See [Stripe docs](https://stripe.com/docs/api/invoices/upcoming) """ @spec upcoming(map, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()} def upcoming(params, opts \\ []) def upcoming(params = %{customer: _customer}, opts), do: get_upcoming(params, opts) def upcoming(params = %{customer_details: _customer_details}, opts), do: get_upcoming(params, opts) def upcoming(params = %{subscription: _subscription}, opts), do: get_upcoming(params, opts) defp get_upcoming(params, opts) do new_request(opts) |> put_endpoint(@plural_endpoint <> "/upcoming") |> put_method(:get) |> put_params(params) |> make_request() end @doc """ List all invoices You can list all invoices, or list the invoices for a specific customer. The invoices are returned sorted by creation date, with the most recently created invoices appearing first. See [Stripe docs](https://stripe.com/docs/api/invoices/list) """ @spec list(params, Stripe.options()) :: {:ok, Stripe.List.t(t)} | {:error, Stripe.Error.t()} when params: %{ optional(:collection_method) => String.t(), optional(:customer) => Stripe.id() | Stripe.Customer.t(), optional(:created) => Stripe.date_query(), optional(:due_date) => Stripe.timestamp(), optional(:ending_before) => t | Stripe.id(), optional(:limit) => 1..100, optional(:starting_after) => t | Stripe.id(), optional(:subscription) => Stripe.id() | Stripe.Subscription.t(), optional(:status) => String.t() } | %{} def list(params \\ %{}, opts \\ []) do new_request(opts) |> put_endpoint(@plural_endpoint) |> put_method(:get) |> put_params(params) |> cast_to_id([:customer, :ending_before, :starting_after, :subscription]) |> make_request() end @doc """ Search invoices See the [Stripe docs](https://stripe.com/docs/api/invoices/search). """ @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 """ Finalize an invoice Stripe automatically finalizes drafts before sending and attempting payment on invoices. However, if you’d like to finalize a draft invoice manually, you can do so using this method. See [Stripe docs](https://stripe.com/docs/api/invoices/finalize) """ @spec finalize(Stripe.id() | t, params, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()} when params: %{ :id => String.t(), optional(:auto_advance) => boolean } | %{} def finalize(id, params, opts \\ []) do new_request(opts) |> prefix_expansions() |> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}/finalize") |> put_method(:post) |> put_params(params) |> cast_to_id([:source]) |> make_request() end @doc """ Pay an invoice Stripe automatically creates and then attempts to collect payment on invoices for customers on subscriptions according to your subscriptions settings. However, if you’d like to attempt payment on an invoice out of the normal collection schedule or for some other reason, you can do so. See [Stripe docs](https://stripe.com/docs/api/invoices/delete) """ @spec pay(Stripe.id() | t, params, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()} when params: %{ :id => String.t(), optional(:forgive) => boolean, optional(:paid_out_of_band) => boolean, optional(:payment_method) => String.t(), optional(:source) => Stripe.id() | Stripe.Source.t(), optional(:off_session) => boolean } | %{} def pay(id, params, opts \\ []) do new_request(opts) |> prefix_expansions() |> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}/pay") |> put_method(:post) |> put_params(params) |> cast_to_id([:source]) |> make_request() end @doc """ Void an invoice Mark a finalized invoice as void. This cannot be undone. Voiding an invoice is similar to deletion, however it only applies to finalized invoices and maintains a papertrail where the invoice can still be found. See [Stripe docs](https://stripe.com/docs/api/invoices/void) """ @spec void(Stripe.id() | t, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()} def void(id, opts \\ []) do new_request(opts) |> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}/void") |> put_method(:post) |> make_request() end @doc """ Send an invoice Stripe will automatically send invoices to customers according to your subscriptions settings. However, if you’d like to manually send an invoice to your customer out of the normal schedule, you can do so. When sending invoices that have already been paid, there will be no reference to the payment in the email. Requests made in test-mode result in no emails being sent, despite sending an `invoice.sent` event. See [Stripe docs](https://stripe.com/docs/api/invoices/send) """ @spec send(Stripe.id() | t, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()} def send(id, opts \\ []) do new_request(opts) |> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}/send") |> put_method(:post) |> make_request() end @doc """ Delete an invoice Permanently deletes a draft invoice. This cannot be undone. Attempts to delete invoices that are no longer in a draft state will fail; once an invoice has been finalized, it must be voided. ## Example {:ok, _} = Stripe.Invoice.delete("in_16vEXC2eZvKYlo2CU9MyflAA") {:ok, _} = Stripe.Invoice.delete(%Stripe.Invoice{id: "in_16vEXC2eZvKYlo2CU9MyflAA"}) See [Stripe docs](https://stripe.com/docs/api/invoices/delete) """ @spec delete(Stripe.id() | t, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()} def delete(id, opts \\ []) do new_request(opts) |> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}") |> put_method(:delete) |> make_request() end @doc """ Mark an invoice as uncollectible Marking an invoice as uncollectible is useful for keeping track of bad debts that can be written off for accounting purposes. ## Example {:ok, _} = Stripe.Invoice.mark_as_uncollectible("in_16vEXC2eZvKYlo2CU9MyflAA") {:ok, _} = Stripe.Invoice.mark_as_uncollectible(%Stripe.Invoice{id: "in_16vEXC2eZvKYlo2CU9MyflAA"}) See [Stripe docs](https://stripe.com/docs/api/invoices/mark_uncollectible) """ @spec mark_as_uncollectible(Stripe.id() | t, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()} def mark_as_uncollectible(id, opts \\ []) do new_request(opts) |> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}/mark_uncollectible") |> put_method(:post) |> make_request() end end