Skip to content

Commit

Permalink
add payment intents (beam-community#470)
Browse files Browse the repository at this point in the history
  • Loading branch information
christian-froh authored and jalexander committed Nov 18, 2024
1 parent 89a74a4 commit 2b5c5b6
Show file tree
Hide file tree
Showing 5 changed files with 356 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/stripe/converter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ defmodule Stripe.Converter do
oauth
order
order_return
payment_intent
payout
plan
product
Expand Down
10 changes: 10 additions & 0 deletions lib/stripe/core_resources/charge.ex
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ defmodule Stripe.Charge do
address_zip: String.t() | nil
}

@type transfer_data :: %{
:amount => non_neg_integer,
:destination => String.t()
}

@type t :: %__MODULE__{
id: Stripe.id(),
object: String.t(),
Expand All @@ -77,6 +82,7 @@ defmodule Stripe.Charge do
order: Stripe.id() | Stripe.Order.t() | nil,
outcome: charge_outcome | nil,
paid: boolean,
payment_intent: Stripe.id() | Stripe.PaymentIntent.t() | nil,
receipt_email: String.t() | nil,
receipt_number: String.t() | nil,
receipt_url: String.t() | nil,
Expand All @@ -89,6 +95,7 @@ defmodule Stripe.Charge do
statement_descriptor: String.t() | nil,
status: String.t(),
transfer: Stripe.id() | Stripe.Transfer.t() | nil,
transfer_data: transfer_data | nil,
transfer_group: String.t() | nil
}

Expand Down Expand Up @@ -117,6 +124,7 @@ defmodule Stripe.Charge do
:order,
:outcome,
:paid,
:payment_intent,
:receipt_email,
:receipt_number,
:receipt_url,
Expand All @@ -129,6 +137,7 @@ defmodule Stripe.Charge do
:statement_descriptor,
:status,
:transfer,
:transfer_data,
:transfer_group
]

Expand All @@ -155,6 +164,7 @@ defmodule Stripe.Charge do
:account => Stripe.id() | Stripe.Account.t(),
optional(:amount) => non_neg_integer
},
optional(:transfer_data) => transfer_data,
optional(:transfer_group) => String.t(),
optional(:on_behalf_of) => Stripe.id() | Stripe.Account.t(),
optional(:metadata) => map,
Expand Down
294 changes: 294 additions & 0 deletions lib/stripe/core_resources/payment_intent.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
defmodule Stripe.PaymentIntent do
@moduledoc """
Work with [Stripe `payment_intent` objects](https://stripe.com/docs/api/payment_intents).
You can:
- [Create a payment_intent](https://stripe.com/docs/api/payment_intents/create)
- [Retrieve a payment_intent](https://stripe.com/docs/api/payment_intents/retrieve)
- [Update a payment_intent](https://stripe.com/docs/api/payment_intents/update)
- [Confirm a payment_intent](https://stripe.com/docs/api/payment_intents/confirm)
- [Capture a payment_intent](https://stripe.com/docs/api/payment_intents/capture)
- [Cancel a payment_intent](https://stripe.com/docs/api/payment_intents/cancel)
- [List all payment_intent](https://stripe.com/docs/api/payment_intents/list)
"""

use Stripe.Entity
import Stripe.Request
require Stripe.Util

@type last_payment_error :: %{
type: String.t(),
charge: String.t(),
code: String.t(),
decline_code: String.t(),
doc_url: String.t(),
message: String.t(),
param: String.t(),
payment_intent: Stripe.PaymentIntent.t() | map,
source: Stripe.Card.t() | map
}

@type next_action :: %{
redirect_to_url: redirect_to_url | nil,
type: String.t(),
use_stripe_sdk: map | nil
}

@type redirect_to_url :: %{
return_url: String.t(),
url: String.t()
}

@type transfer_data :: %{
:destination => String.t()
}

@type t :: %__MODULE__{
id: Stripe.id(),
object: String.t(),
amount: non_neg_integer,
amount_capturable: non_neg_integer,
amount_received: non_neg_integer,
application: Stripe.id() | nil,
application_fee_amount: non_neg_integer | nil,
canceled_at: Stripe.timestamp() | nil,
cancellation_reason: String.t() | nil,
capture_method: String.t(),
charges: Stripe.List.t(Stripe.Charge.t()),
client_secret: String.t(),
confirmation_method: String.t(),
created: Stripe.timestamp(),
currency: String.t(),
customer: Stripe.id() | Stripe.Customer.t() | nil,
description: String.t() | nil,
last_payment_error: last_payment_error | nil,
livemode: boolean,
metadata: Stripe.Types.metadata(),
next_action: next_action | nil,
on_behalf_of: Stripe.id() | Stripe.Account.t() | nil,
payment_method_types: list(String.t()),
receipt_email: String.t() | nil,
review: Stripe.id() | Stripe.Review.t() | nil,
shipping: Stripe.Types.shipping() | nil,
source: Stripe.Card.t() | map,
statement_descriptor: String.t() | nil,
status: String.t(),
transfer_data: transfer_data | nil,
transfer_group: String.t() | nil
}

defstruct [
:id,
:object,
:amount,
:amount_capturable,
:amount_received,
:application,
:application_fee_amount,
:canceled_at,
:cancellation_reason,
:capture_method,
:charges,
:client_secret,
:confirmation_method,
:created,
:currency,
:customer,
:description,
:last_payment_error,
:livemode,
:metadata,
:next_action,
:on_behalf_of,
:payment_method_types,
:receipt_email,
:review,
:shipping,
:source,
:statement_descriptor,
:status,
:transfer_data,
:transfer_group
]

@plural_endpoint "payment_intents"

@doc """
Create a payment intent.
See the [Stripe docs](https://stripe.com/docs/api/payment_intents/create).
"""
@spec create(params, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
when params:
%{
:amount => pos_integer,
:currency => String.t(),
:payment_method_types => [String.t()],
optional(:application_fee_amount) => non_neg_integer,
optional(:capture_method) => String.t(),
optional(:confirm) => boolean,
optional(:customer) => Stripe.id() | Stripe.Customer.t(),
optional(:description) => String.t(),
optional(:metadata) => map,
optional(:on_behalf_of) => Stripe.id() | Stripe.Account.t(),
optional(:receipt_email) => String.t(),
optional(:return_url) => String.t(),
optional(:save_payment_method) => boolean,
optional(:shipping) => Stripe.Types.shipping(),
optional(:source) => Stripe.id() | Stripe.Card.t(),
optional(:statement_descriptor) => String.t(),
optional(:transfer_data) => transfer_data,
optional(:transfer_group) => String.t()
}
| %{}
def create(params, opts \\ []) do
new_request(opts)
|> put_endpoint(@plural_endpoint)
|> put_params(params)
|> put_method(:post)
|> cast_path_to_id([:destination, :account])
|> cast_to_id([:on_behalf_of, :customer, :source])
|> make_request()
end

@doc """
Retrieves the details of a PaymentIntent that has previously been created.
Client-side retrieval using a publishable key is allowed when the client_secret is provided in the query string.
When retrieved with a publishable key, only a subset of properties will be returned. Please refer to the payment intent object reference for more details.
See the [Stripe docs](https://stripe.com/docs/api/payment_intents/retrieve).
"""
@spec retrieve(Stripe.id() | t, params, Stripe.options()) ::
{:ok, t} | {:error, Stripe.Error.t()}
when params:
%{
:client_secret => String.t()
}
| %{}
def retrieve(id, params, opts \\ []) do
new_request(opts)
|> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}")
|> put_params(params)
|> put_method(:get)
|> make_request()
end

@doc """
Updates a PaymentIntent object.
See the [Stripe docs](https://stripe.com/docs/api/payment_intents/update).
"""
@spec update(Stripe.id() | t, params, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
when params:
%{
optional(:amount) => non_neg_integer,
optional(:application_fee_amount) => non_neg_integer,
optional(:currency) => String.t(),
optional(:customer) => Stripe.id() | Stripe.Customer.t(),
optional(:description) => String.t(),
optional(:metadata) => map,
optional(:payment_method_types) => [Stripe.id()],
optional(:receipt_email) => String.t(),
optional(:save_payment_method) => boolean,
optional(:shipping) => Stripe.Types.shipping(),
optional(:source) => Stripe.id() | Stripe.Card.t(),
optional(:transfer_group) => 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 """
Confirm that your customer intends to pay with current or provided source. Upon confirmation,
the PaymentIntent will attempt to initiate a payment.
If the selected source requires additional authentication steps, the PaymentIntent will transition to
the requires_action status and suggest additional actions via next_source_action.
If payment fails, the PaymentIntent will transition to the requires_payment_method status.
If payment succeeds, the PaymentIntent will transition to the succeeded status (or requires_capture,
if capture_method is set to manual). Read the expanded documentation to learn more about server-side confirmation.
See the [Stripe docs](https://stripe.com/docs/api/payment_intents/confirm).
"""
@spec confirm(Stripe.id() | t, params, Stripe.options()) ::
{:ok, t} | {:error, Stripe.Error.t()}
when params:
%{
:client_secret => String.t(),
optional(:receipt_email) => String.t(),
optional(:return_url) => String.t(),
optional(:save_payment_method) => boolean,
optional(:shipping) => Stripe.Types.shipping(),
optional(:source) => Stripe.id() | Stripe.Card.t()
}
| %{}
def confirm(id, params, opts \\ []) do
new_request(opts)
|> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}" <> "/confirm")
|> put_method(:post)
|> put_params(params)
|> make_request()
end

@doc """
Capture the funds of an existing uncaptured PaymentIntent where required_action="requires_capture".
Uncaptured PaymentIntents will be canceled exactly seven days after they are created.
See the [Stripe docs](https://stripe.com/docs/api/payment_intents/capture).
"""
@spec capture(Stripe.id() | t, params, Stripe.options()) ::
{:ok, t} | {:error, Stripe.Error.t()}
when params:
%{
optional(:amount_to_capture) => non_neg_integer,
optional(:application_fee_amount) => non_neg_integer
}
| %{}
def capture(id, params, opts \\ []) do
new_request(opts)
|> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}/capture")
|> put_params(params)
|> put_method(:post)
|> make_request()
end

@doc """
A PaymentIntent object can be canceled when it is in one of these statuses: requires_payment_method,
requires_capture, requires_confirmation, requires_action.
Once canceled, no additional charges will be made by the PaymentIntent and any operations on the PaymentIntent will fail with an error.
For PaymentIntents with status='requires_capture', the remaining amount_capturable will automatically be refunded.
See the [Stripe docs](https://stripe.com/docs/api/payment_intents/cancel).
"""
@spec cancel(Stripe.id() | t, params, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
when params:
%{
optional(:cancellation_reason) => String.t()
}
| %{}
def cancel(id, params, opts \\ []) do
new_request(opts)
|> put_endpoint(@plural_endpoint <> "/#{get_id!(id)}" <> "/cancel")
|> put_method(:post)
|> put_params(params)
|> make_request()
end

@doc """
Returns a list of PaymentIntents.
See the [Stripe docs](https://stripe.com/docs/api/payment_intents/list).
"""
@spec list(params, Stripe.options()) :: {:ok, Stripe.List.t(t)} | {:error, Stripe.Error.t()}
when params: %{
optional(:created) => Stripe.date_query(),
optional(:ending_before) => t | Stripe.id(),
optional(:limit) => 1..100,
optional(:starting_after) => t | Stripe.id()
}
def list(params \\ %{}, opts \\ []) do
new_request(opts)
|> prefix_expansions()
|> put_endpoint(@plural_endpoint)
|> put_method(:get)
|> put_params(params)
|> cast_to_id([:ending_before, :starting_after])
|> make_request()
end
end
Loading

0 comments on commit 2b5c5b6

Please sign in to comment.