Skip to content

Commit

Permalink
invoice items
Browse files Browse the repository at this point in the history
  • Loading branch information
slogsdon committed Mar 31, 2014
1 parent ee4c186 commit c6f2c82
Show file tree
Hide file tree
Showing 10 changed files with 439 additions and 0 deletions.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# stripe-elixir

a Stripe wrapper for Elixir

## Usage

> ##### Note
> stripe-elixir requires the `STRIPE_SECRET_KEY` environment variable set to a
> valid API key associated with your Stripe account.
```elixir
iex> Stripe.start
:ok
iex> Stripe.InvoiceItems.list
[Stripe.InvoiceItem[id: "ii_103lSZ2eZvKYlo2C6Zz1aFHv", object: "invoiceitem",
livemode: false, amount: 1000, currency: "usd",
customer: "cus_3lPWbj9wX1KqP6", date: {{2014, 3, 30}, {3, 0, 11}},
proration: false, description: "One-time setup fee", invoice: nil,
metadata: [{}], subscription: nil],
Stripe.InvoiceItem[id: "ii_103kXf2eZvKYlo2CkRlaXEN6", object: "invoiceitem",
livemode: false, amount: 350, currency: "usd", customer: "cus_3kXfWSyHPMZOan",
date: {{2014, 3, 27}, {16, 11, 35}}, proration: false, description: nil,
invoice: "in_103kXf2eZvKYlo2CgUV8Vctw", metadata: [{}], subscription: nil],
...]
```

## Reference

See [Stripe's API docs](https://stripe.com/docs/api/).

## Dependencies

- [HTTPoison](https://github.com/edgurgel/httpoison)
- [JSEX](https://github.com/talentdeficit/jsex)

## License

See [LICENSE](https://github.com/slogsdon/stripe-elixir/blob/master/LICENSE)
83 changes: 83 additions & 0 deletions lib/stripe.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
defmodule Stripe do
@moduledoc """
A HTTP client for Stripe.
"""

# Let's build on top of HTTPoison
use Application.Behaviour
use HTTPoison.Base

def start(_type, _args) do
Stripe.Supervisor.start_link
end

@doc """
Creates the URL for our endpoint.
Args:
* endpoint - part of the API we're hitting
Returns string
"""
def process_url(endpoint) do
"https://api.stripe.com/v1/" <> endpoint
end

@doc """
Set our request headers for every request.
"""
def req_headers do
HashDict.new
|> Dict.put("Authorization", "Bearer #{key}")
|> Dict.put("User-Agent", "Stripe/v1 stripe-elixir/0.1.0")
|> Dict.put("Content-Type", "application/x-www-form-urlencoded")
end

@doc """
Converts the binary keys in our response to atoms.
Args:
* body - string binary response
Returns Record or ArgumentError
"""
def process_response_body(body) do
JSEX.decode! body, [{:labels, :atom}]
end

@doc """
Boilerplate code to make requests.
Args:
* endpoint - string requested API endpoint
* body - request body
Returns dict
"""
def make_request(method, endpoint, body // [], headers // [], options // []) do
rb = Enum.map(body, &url_encode_keyvalue(&1))
|> Enum.join("&")
rh = req_headers
|> Dict.merge(headers)
|> Dict.to_list

response = case method do
:get -> get( endpoint, rh, options)
:put -> put( endpoint, rb, rh, options)
:head -> head( endpoint, rh, options)
:post -> post( endpoint, rb, rh, options)
:patch -> patch( endpoint, rb, rh, options)
:delete -> delete( endpoint, rh, options)
:options -> options( endpoint, rh, options)
end

response.body
end

@doc """
Grabs STRIPE_SECRET_KEY from system ENV
Returns binary
"""
def key do
System.get_env "STRIPE_SECRET_KEY"
end

defp url_encode_keyvalue({k, v}) do
key = atom_to_binary(k)
"#{key}=#{v}"
end
end
80 changes: 80 additions & 0 deletions lib/stripe/invoice_item.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
defrecord Stripe.InvoiceItem,
id: nil,
object: "invoiceitem",
livemode: nil,
amount: nil,
currency: nil,
customer: nil,
date: nil,
proration: nil,
description: nil,
invoice: nil,
metadata: nil,
subscription: nil do

@type id :: binary
@type object :: binary
@type livemode :: nil
@type amount :: nil
@type currency :: binary
@type customer :: binary
@type date :: {{1970..10000, 1..12, 1..31}, {0..23, 0..59, 0..59}}
@type proration :: nil
@type description :: binary
@type invoice :: binary
@type metadata :: Keyword.t
@type subscription :: binary

record_type id: id,
object: object,
livemode: livemode,
amount: amount,
currency: currency,
customer: customer,
date: date,
proration: proration,
description: description,
invoice: invoice,
metadata: metadata,
subscription: subscription

@moduledoc """
## Attributes
- `id` - `String`
- `object` - `String`, value is "invoiceitem"
- `livemode` - `Boolean`
- `amount` - `Integer`
- `currency` - `String`
- `customer` - `String`
- `date` - `Tuple`
- `proration` - `Boolean` - Whether or not the invoice item was created
automatically as a proration adjustment when the customer
switched plans
- `description` - `String`
- `invoice` - `String`
- `metadata` - `Keyword` - A set of key/value pairs that you can
attach to an invoice item object. It can be useful for storing
additional information about the invoice item in a structured format.
- `subscription` - `String` - The subscription that this invoice item
has been created for, if any.
"""

def from_keyword(data) do
datetime = Stripe.Util.datetime_from_timestamp data[:date]
Stripe.InvoiceItem.new(
id: data[:id],
object: data[:object],
livemode: data[:livemode],
amount: data[:amount],
currency: data[:currency],
customer: data[:customer],
date: datetime,
proration: data[:proration],
description: data[:description],
invoice: data[:invoice],
metadata: data[:metadata],
subscription: data[:subscription]
)
end
end
172 changes: 172 additions & 0 deletions lib/stripe/invoice_items.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
defmodule Stripe.InvoiceItems do
@moduledoc """
Invoice Items
Sometimes you want to add a charge or credit to a customer but only
actually charge the customer's card at the end of a regular billing
cycle. This is useful for combining several charges to minimize
per-transaction fees or having Stripe tabulate your usage-based
billing totals.
"""

@endpoint "invoiceitems"

@doc """
Returns a list of your invoice items. Invoice Items are returned sorted
by creation date, with the most recently created invoice items appearing
first.
## Arguments
- `created` - `String` | `Keyword` - (optional) - A filter on the list
based on the object created field. The value can be a string with
an exact UTC timestamp, or it can be a dictionary with the
following options:
- `gt` - `String` - (optional) - Return values where the created
field is after this timestamp.
- `gte` - `String` - (optional) - Return values where the created
field is after or equal to this timestamp.
- `lt` - `String` - (optional) - Return values where the created
field is before this timestamp.
- `lte` - `String` - (optional) - Return values where the created
field is before or equal to this timestamp.
- `customer` - `String` - (optional) - The identifier of the customer
whose invoice items to return. If none is provided, all invoice
items will be returned.
- `limit` - `Integer` - (optional), default is 10 - A limit on the number
of objects to be returned. Limit can range between 1 and 100 items.
- `offset` - `Integer` - (optional), default is 0 - An offset into the
list of returned items. The API will return the requested number of
items starting at that offset.
- `starting_after` - `String` - (optional) - A "cursor" for use in
pagination. starting_after is an object id that defines your place
in the list. For instance, if you make a list request and receive
100 objects, ending with obj_foo, your subsequent call can include
`starting_after=obj_foo` in order to fetch the next page of the list.
## Returns
A dictionary with a data property that contains an array of up to limit
invoice items, starting after invoice item starting_after. Each entry in
the array is a separate invoice item object. If no more invoice items
are available, the resulting array will be empty. This request should
never return an error.
You can optionally request that the response include the total count of
all invoice items that match your filters. To do so, specify
`include[]=total_count` in your request.
"""
def list do
obj = Stripe.make_request :get, @endpoint
if obj[:data] do
Enum.map obj[:data], &Stripe.InvoiceItem.from_keyword(&1)
else
[]
end
end

@doc """
Adds an arbitrary charge or credit to the customer's upcoming invoice.
## Arguments
- `customer` - `String` - (required) - The ID of the customer who will
be billed when this invoice item is billed.
- `amount` - `Integer` - (required) - The integer amount in cents of
the charge to be applied to the upcoming invoice. If you want to
apply a credit to the customer's account, pass a negative amount.
- `currency` - `String` - (required) - 3-letter ISO code for currency.
- `invoice` - `String` - (optional) - The ID of an existing invoice to
add this invoice item to. When left blank, the invoice item will be
added to the next upcoming scheduled invoice. Use this when adding
invoice items in response to an invoice.created webhook. You
cannot add an invoice item to an invoice that has already been
paid or closed.
- `subscription` - `String` - (optional) - The ID of a subscription to
add this invoice item to. When left blank, the invoice item will be
added to the next upcoming scheduled invoice. When set, scheduled
invoices for subscriptions other than the specified subscription
will ignore the invoice item. Use this when you want to express
that an invoice item has been accrued within the context of a
particular subscription.
- `description` - `String` - (optional), default is `null` - An arbitrary
string which you can attach to the invoice item. The description is
displayed in the invoice for easy tracking.
- `metadata` - `Keyword` - (optional), default is `[]` - A set of
key/value pairs that you can attach to an invoice item object. It can
be useful for storing additional information about the invoice item in
a structured format.
## Returns
The created invoice item object is returned if successful. Otherwise,
this call returns an error.
"""
def create(params) do
obj = Stripe.make_request :post, @endpoint, params
Stripe.InvoiceItem.from_keyword obj
end

@doc """
Retrieves the invoice item with the given ID.
## Arguments
- `id` - `String` - (required) - The ID of the desired invoice item.
## Returns
Returns an invoice item if a valid invoice item ID was provided. Returns
an error otherwise.
"""
def retrieve(id) do
obj = Stripe.make_request :get, @endpoint <> "/#{id}"
Stripe.InvoiceItem.from_keyword obj
end

@doc """
Updates the amount or description of an invoice item on an upcoming invoice.
Updating an invoice item is only possible before the invoice it's attached
to is closed.
## Arguments
- `amount` - `Integer` - (required) - The integer amount in cents of
the charge to be applied to the upcoming invoice. If you want to
apply a credit to the customer's account, pass a negative amount.
- `description` - `String` - (optional), default is `null` - An arbitrary
string which you can attach to the invoice item. The description is
displayed in the invoice for easy tracking.
- `metadata` - `Keyword` - (optional), default is `[]` - A set of
key/value pairs that you can attach to an invoice item object. It can
be useful for storing additional information about the invoice item in
a structured format.
## Returns
The updated invoice item object is returned upon success. Otherwise, this
call returns an error.
"""
def update(params) do
obj = Stripe.make_request :post, @endpoint <> "/#{params[:id]}", params
Stripe.InvoiceItem.from_keyword obj
end

@doc """
Removes an invoice item from the upcoming invoice. Removing an invoice
item is only possible before the invoice it's attached to is closed.
## Arguments
- `id` - `String` - (required) - The ID of the desired invoice item.
## Returns
An object with the deleted invoice item's ID and a deleted flag upon
success. This call returns an error otherwise, such as when the invoice
item has already been deleted.
"""
def delete(id) do
Stripe.make_request :delete, @endpoint <> "/#{id}"
end
end
18 changes: 18 additions & 0 deletions lib/stripe/supervisor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule Stripe.Supervisor do
use Supervisor.Behaviour

def start_link do
:supervisor.start_link(__MODULE__, [])
end

def init([]) do
children = [
# Define workers and child supervisors to be supervised
# worker(Stripe.Worker, [])
]

# See http://elixir-lang.org/docs/stable/Supervisor.Behaviour.html
# for other strategies and supported options
supervise(children, strategy: :one_for_one)
end
end
Loading

0 comments on commit c6f2c82

Please sign in to comment.