Skip to content

Commit

Permalink
Add ExternalAccount endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
joshsmith committed Nov 25, 2017
1 parent 9e99933 commit 7d5b9e0
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 73 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ before_install:
script: mix coveralls.travis
after_script:
- mix inch.report
notifications:
email:
on_success: never
12 changes: 2 additions & 10 deletions lib/stripe/connect/account.ex
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,7 @@ defmodule Stripe.Account do
decline_charge_on: decline_charge_on | nil,
default_currency: String.t() | nil,
email: String.t() | nil,
external_account:
Stripe.ExternalAccount.create_params_for_bank_account()
| Stripe.ExternalAccount.create_params_for_card()
| String.t()
| nil,
external_account: String.t() | nil,
legal_entity: legal_entity,
metadata: Stripe.Types.metadata() | nil,
payout_schedule: Stripe.Types.transfer_schedule() | nil,
Expand Down Expand Up @@ -253,11 +249,7 @@ defmodule Stripe.Account do
decline_charge_on: decline_charge_on | nil,
default_currency: String.t() | nil,
email: String.t() | nil,
external_account:
Stripe.ExternalAccount.create_params_for_bank_account()
| Stripe.ExternalAccount.create_params_for_card()
| String.t()
| nil,
external_account: String.t() | nil,
legal_entity: legal_entity,
metadata: Stripe.Types.metadata() | nil,
payout_schedule: Stripe.Types.transfer_schedule() | nil,
Expand Down
131 changes: 68 additions & 63 deletions lib/stripe/connect/external_account.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,104 +9,109 @@ defmodule Stripe.ExternalAccount do
- Update an external account
- Delete an external account
Does not yet render lists or take options.
Probably does not yet work for credit cards.
Stripe API reference: https://stripe.com/docs/api#external_accounts
"""

alias Stripe.Util
import Stripe.Request

defp endpoint(managed_account_id) do
"accounts/#{managed_account_id}/external_accounts"
defp accounts_plural_endpoint(%{account: id}) do
"accounts/#{id}/external_accounts"
end

@type t :: Stripe.BankAccount.t() | Stripe.Card.t()

@type create_params :: %{
external_account:
create_params_for_bank_account
| create_params_for_card
| String.t(),
default_for_currency: boolean | nil,
external_account: String.t(),
metadata: Stripe.Types.metadata() | nil
}

@type create_params_for_bank_account :: %{
object: String.t(),
account_number: String.t(),
country: String.t(),
currency: String.t(),
account_holder_name: String.t() | nil,
account_holder_type: String.t() | nil,
routing_number: String.t() | nil
}

@type create_params_for_card :: %{
object: String.t(),
exp_month: String.t(),
exp_year: String.t(),
number: String.t(),
address_city: String.t() | nil,
address_country: String.t() | nil,
address_line1: String.t() | nil,
address_line2: String.t() | nil,
address_state: String.t() | nil,
address_zip: String.t() | nil,
currency: String.t() | nil,
cvc: String.t() | nil,
default_for_currency: String.t() | nil,
metadata: Stripe.Types.metadata() | nil,
name: String.t() | nil
}

@doc """
Create an external account.
Only accepts a `token` and not a hash of values.
"""
@spec create(map, Keyword.t()) :: {:ok, t} | {:error, Stripe.api_error_struct()}
def create(changes, opts = [connect_account: managed_account_id]) do
endpoint = endpoint(managed_account_id)
Stripe.Request.create(endpoint, changes, opts)
@spec create(map, Keyword.t()) :: {:ok, t} | {:error, Stripe.Error.t()}
def create(%{account: _, token: token} = params, opts \\ []) do
endpoint = params |> accounts_plural_endpoint()

updated_params =
params
|> Map.put(:external_account, token)
|> Map.delete(:token)
|> Map.delete(:account)

new_request(opts)
|> put_endpoint(endpoint)
|> put_params(updated_params)
|> put_method(:post)
|> make_request()
end

@doc """
Retrieve an external account.
"""
@spec retrieve(String.t(), Keyword.t()) :: {:ok, t} | {:error, Stripe.api_error_struct()}
def retrieve(id, opts = [connect_account: managed_account_id]) do
endpoint = endpoint(managed_account_id) <> "/" <> id
Stripe.Request.retrieve(endpoint, opts)
@spec retrieve(Stripe.id() | t, map, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
def retrieve(id, %{account: _} = params, opts \\ []) do
endpoint = params |> accounts_plural_endpoint()

new_request(opts)
|> put_endpoint(endpoint <> "/#{get_id!(id)}")
|> put_method(:get)
|> make_request()
end

@doc """
Update an external account.
Takes the `id` and a map of changes.
"""
@spec update(String.t(), map, list) :: {:ok, t} | {:error, Stripe.api_error_struct()}
def update(id, changes, opts = [connect_account: managed_account_id]) do
endpoint = endpoint(managed_account_id) <> "/" <> id
Stripe.Request.update(endpoint, changes, opts)
@spec update(Stripe.id() | t, map, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
def update(id, %{account: _} = params, opts \\ []) do
endpoint = params |> accounts_plural_endpoint()

new_request(opts)
|> put_endpoint(endpoint <> "/#{get_id!(id)}")
|> put_method(:post)
|> put_params(params |> Map.delete(:account))
|> make_request()
end

@doc """
Delete an external account.
"""
@spec delete(t | String.t(), list) :: :ok | {:error, Stripe.api_error_struct()}
def delete(account, opts = [connect_account: managed_account_id]) do
id = Util.normalize_id(account)
endpoint = endpoint(managed_account_id) <> "/" <> id
Stripe.Request.delete(endpoint, %{}, opts)
@spec delete(Stripe.id() | t, map, Stripe.options()) :: {:ok, t} | {:error, Stripe.Error.t()}
def delete(id, %{account: _} = params, opts \\ []) do
endpoint = params |> accounts_plural_endpoint()

new_request(opts)
|> put_endpoint(endpoint <> "/#{get_id!(id)}")
|> put_method(:delete)
|> make_request()
end

@doc """
List all external accounts.
Takes either `:bank_account` or `:card` to determine which object to list.
"""
@spec list(map, Keyword.t()) :: {:ok, Stripe.List.t()} | {:error, Stripe.api_error_struct()}
def list(params \\ %{}, opts = [connect_account: managed_account_id]) do
endpoint = endpoint(managed_account_id)
params = Map.merge(params, %{"object" => "bank_account"})
Stripe.Request.retrieve(params, endpoint, opts)
@spec list(atom, map, Stripe.options()) :: {:ok, Stripe.List.of(t)} | {:error, Stripe.Error.t()}
def list(atom, params, opts \\ [])
def list(:bank_account, %{account: _} = params, opts) do
endpoint = params |> accounts_plural_endpoint()
params = params |> Map.put(:object, "bank_account")
do_list(endpoint, params, opts)
end
def list(:card, %{account: _} = params, opts) do
endpoint = params |> accounts_plural_endpoint()
params = params |> Map.put(:object, "card")
do_list(endpoint, params, opts)
end

@spec do_list(String.t, map, Stripe.options()) :: {:ok, Stripe.List.of(t)} | {:error, Stripe.Error.t()}
defp do_list(endpoint, params, opts) do
new_request(opts)
|> put_endpoint(endpoint)
|> put_method(:get)
|> put_params(params |> Map.delete(:account))
|> make_request()
end
end
65 changes: 65 additions & 0 deletions test/stripe/connect/external_account_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
defmodule Stripe.ExternalAccountTest do
use Stripe.StripeCase, async: true

describe "create/2" do
test "creates a bank account for an account" do
{:ok, _} = Stripe.ExternalAccount.create(%{account: "acct_123", token: "tok_stripetestbank"})
assert_stripe_requested(:post, "/v1/accounts/acct_123/external_accounts")
end

test "creates a card for an account" do
{:ok, _} = Stripe.ExternalAccount.create(%{account: "acct_123", token: "tok_amex"})
assert_stripe_requested(:post, "/v1/accounts/acct_123/external_accounts")
end
end

describe "retrieve/2" do
test "retrieves a bank account" do
{:ok, _} = Stripe.ExternalAccount.retrieve("ba_123", %{account: "acct_123"})
assert_stripe_requested(:get, "/v1/accounts/acct_123/external_accounts/ba_123")
end

test "retrieves a card" do
{:ok, _} = Stripe.ExternalAccount.retrieve("card_123", %{account: "acct_123"})
assert_stripe_requested(:get, "/v1/accounts/acct_123/external_accounts/card_123")
end
end

describe "update/2" do
test "updates a bank account" do
{:ok, _} = Stripe.ExternalAccount.update("ba_123", %{account: "acct_123"})
assert_stripe_requested(:post, "/v1/accounts/acct_123/external_accounts/ba_123")
end

test "updates a card" do
{:ok, _} = Stripe.ExternalAccount.update("card_123", %{account: "acct_123"})
assert_stripe_requested(:post, "/v1/accounts/acct_123/external_accounts/card_123")
end
end

describe "delete/2" do
test "deletes a bank account" do
{:ok, _} = Stripe.ExternalAccount.delete("ba_123", %{account: "acct_123"})
assert_stripe_requested(:delete, "/v1/accounts/acct_123/external_accounts/ba_123")
end

test "deletes a card" do
{:ok, _} = Stripe.ExternalAccount.delete("card_123", %{account: "acct_123"})
assert_stripe_requested(:delete, "/v1/accounts/acct_123/external_accounts/card_123")
end
end

describe "list/3" do
test "lists all bank accounts for an account" do
assert {:ok, %Stripe.List{data: bank_accounts}} = Stripe.ExternalAccount.list(:bank_account, %{account: "acct_123"})
assert_stripe_requested(:get, "/v1/accounts/acct_123/external_accounts?object=bank_account")
assert is_list(bank_accounts)
end

test "lists all cards for an account" do
assert {:ok, %Stripe.List{data: cards}} = Stripe.ExternalAccount.list(:card, %{account: "acct_123"})
assert_stripe_requested(:get, "/v1/accounts/acct_123/external_accounts?object=card")
assert is_list(cards)
end
end
end

0 comments on commit 7d5b9e0

Please sign in to comment.