Skip to content

Commit

Permalink
Add Stripe.Customer
Browse files Browse the repository at this point in the history
  • Loading branch information
joshsmith committed Nov 11, 2016
1 parent ad0ed17 commit 98c3cf7
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 15 deletions.
2 changes: 1 addition & 1 deletion lib/stripe.ex
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ defmodule Stripe do
"Accept" => "application/json; charset=utf8",
"Accept-Encoding" => "gzip",
"Authorization" => "Bearer #{api_key}",
"Content-Type" => "applicaton/x-www-form-urlencoded",
"Content-Type" => "application/x-www-form-urlencoded",
"Connection" => "keep-alive",
"User-Agent" => "Stripe/v1 stripity-stripe/#{@api_version}"
})
Expand Down
13 changes: 6 additions & 7 deletions lib/stripe/account.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ defmodule Stripe.Account do
Stripe API reference: https://stripe.com/docs/api#account
"""

alias Stripe.Util

@type t :: %__MODULE__{}

defstruct [
Expand All @@ -36,17 +34,18 @@ defmodule Stripe.Account do
@doc """
Retrieve your own account with options.
"""
@spec retrieve(Keyword.t) :: {:ok, t} | {:error, Exception.t}
def retrieve(opts), do: do_retrieve(@singular_endpoint, opts)
@spec retrieve(list) :: {:ok, t} | {:error, Exception.t}
def retrieve(opts) when is_list(opts), do: do_retrieve(@singular_endpoint, opts)

@doc """
Retrieve an account with a specified `id`.
"""
@spec retrieve(binary, Keyword.t) :: {:ok, t} | {:error, Exception.t}
@spec retrieve(binary, list) :: {:ok, t} | {:error, Exception.t}
def retrieve(id, opts \\ []), do: do_retrieve(@plural_endpoint <> "/" <> id, opts)

@spec do_retrieve(String.t, Keyword.t) :: {:ok, t} | {:error, Exception.t}
defp do_retrieve(endpoint, opts) do
@spec do_retrieve(String.t, list) :: {:ok, t} | {:error, Exception.t}
defp do_retrieve(endpoint, opts \\ []) do
IO.inspect opts
case Stripe.request(:get, endpoint, %{}, %{}, opts) do
{:ok, result} -> {:ok, to_struct(result)}
{:error, error} -> {:error, error}
Expand Down
120 changes: 120 additions & 0 deletions lib/stripe/customer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
defmodule Stripe.Customer do
@moduledoc """
Work with Stripe customer objects.
You can:
- Create a customer
- Retrieve a customer
- Update a customer
- Delete a customer
Stripe API reference: https://stripe.com/docs/api#customer
"""

alias Stripe.Util

@type t :: %__MODULE__{}

defstruct [
:id, :account_balance, :business_vat_id, :created, :currency,
:default_source, :delinquent, :description, :discount, :email, :livemode,
:metadata, :shipping, :sources, :subscriptions
]

@plural_endpoint "customers"

@valid_create_keys [
:account_balance, :business_vat_id, :coupon, :description, :email,
:metadata, :plan, :quantity, :shipping, :source, :tax_percent, :trial_end
]

@valid_update_keys [
:account_balance, :business_vat_id, :coupon, :default_source, :description,
:email, :metadata, :shipping, :source
]

@doc """
Create a customer.
"""
@spec create(t, Keyword.t) :: {:ok, t} | {:error, Exception.t}
def create(customer, opts \\ []) do
endpoint = @plural_endpoint

customer =
Map.from_struct(customer)
|> Map.take(@valid_create_keys)
|> Util.drop_nil_keys()

case Stripe.request(:post, endpoint, customer, %{}, opts) do
{:ok, result} -> {:ok, to_struct(result)}
{:error, error} -> {:error, error}
end
end

@doc """
Retrieve a customer.
"""
@spec retrieve(binary, Keyword.t) :: {:ok, t} | {:error, Exception.t}
def retrieve(id, opts \\ []) do
endpoint = @plural_endpoint <> "/" <> id
case Stripe.request(:get, endpoint, %{}, %{}, opts) do
{:ok, result} -> {:ok, to_struct(result)}
{:error, error} -> {:error, error}
end
end

@doc """
Update a customer.
Takes the `id` and a map of changes.
"""
@spec update(t, map, list) :: {:ok, t} | {:error, Exception.t}
def update(id, changes, opts \\ []) do
endpoint = @plural_endpoint <> "/" <> id

customer =
changes
|> Util.map_keys_to_atoms()
|> Map.take(@valid_update_keys)
|> Util.drop_nil_keys()

case Stripe.request(:post, endpoint, customer, %{}, opts) do
{:ok, result} -> {:ok, to_struct(result)}
{:error, error} -> {:error, error}
end
end

@doc """
Delete a customer.
"""
@spec delete(binary, list) :: :ok | {:error, Exception.t}
def delete(id, opts \\ []) do
endpoint = @plural_endpoint <> "/" <> id

case Stripe.request(:delete, endpoint, %{}, %{}, opts) do
{:ok, _} -> :ok
{:error, error} -> {:error, error}
end
end

defp to_struct(response) do
%__MODULE__{
id: Map.get(response, "id"),
account_balance: Map.get(response, "account_balance"),
business_vat_id: Map.get(response, "business_vat_id"),
created: Util.get_date(response, "created"),
currency: Map.get(response, "currency"),
default_source: Map.get(response, "default_source"),
delinquent: Map.get(response, "delinquent"),
description: Map.get(response, "description"),
discount: Map.get(response, "discount"),
email: Map.get(response, "email"),
livemode: Map.get(response, "livemode"),
metadata: Map.get(response, "metadata"),
shipping: Map.get(response, "shipping"),
sources: Map.get(response, "sources"),
subscriptions: Map.get(response, "subscriptions")
}
end
end
55 changes: 48 additions & 7 deletions lib/stripe/util.ex
Original file line number Diff line number Diff line change
@@ -1,28 +1,69 @@
defmodule Stripe.Util do

def drop_nil_keys(map) do
Enum.reject(map, fn
{_, nil} -> true
_ -> false
end)
|> Enum.into(%{})
end

@spec get_date(map, atom | String.t) :: DateTime.t | nil
def get_date(m, k) do
case Map.get(m, k) do
nil -> nil
ts -> DateTime.from_unix!(ts)
ts -> datetime_from_timestamp(ts)
end
end

def datetime_from_timestamp(ts) when is_binary ts do
defp datetime_from_timestamp(ts) when is_binary ts do
ts = case Integer.parse ts do
:error -> 0
{i, _r} -> i
end
datetime_from_timestamp ts
end

def datetime_from_timestamp(ts) when is_number ts do
{{year, month, day}, {hour, minutes, seconds}} = :calendar.gregorian_seconds_to_datetime ts
{{year + 1970, month, day}, {hour, minutes, seconds}}
defp datetime_from_timestamp(ts) when is_number ts do
DateTime.from_unix!(ts)
end

def datetime_from_timestamp(nil) do
datetime_from_timestamp 0
@doc """
Performs a root-level conversion of map keys from strings to atoms.
This function performs the transformation safely using `String.to_existing_atom/1`, but this has a possibility to raise if
there is not a corresponding atom.
It is recommended that you pre-filter maps for known values before
calling this function.
## Examples
iex> map = %{
...> "a"=> %{
...> "b" => %{
...> "c" => 1
...> }
...> }
...> }
iex> Stripe.Util.map_keys_to_atoms(map)
%{
a: %{
"b" => %{
"c" => 1
}
}
}
"""
def map_keys_to_atoms(m) do
Enum.map(m, fn
{k, v} when is_binary(k) ->
a = String.to_existing_atom(k)
{a, v}
entry ->
entry
end)
|> Enum.into(%{})
end

def string_map_to_atoms([string_key_map]) do
Expand Down

0 comments on commit 98c3cf7

Please sign in to comment.