README.md

# ConektaEx
Conekta API Client for Elixir

## Installation

  1. Add `conekta_ex` to deps in `mix.exs`:

```elixir
def deps do
  [
    {:conekta_ex, "~> 1.0.0"}
  ]
end
```

  2. Add your `private_key` to your config file
```elixir
config :conekta_ex, :private_key, "PRIVATE_KEY"

# Optional Config
## locale, Default "es", ref -> https://developers.conekta.com/api#locale
config :conekta_ex, :locale, "en"
## timeout to establish a connection, in milliseconds, Default 15_000
config :conekta_ex, :timeout, 10_000
## recv_timeout used when receiving a connection. Default is 15_000
config :conekta_ex, :recv_timeout, 10_000
```

## Usage

### Card Payments
Allways check for the Order `payment_status` on :ok responses

Payment with a Customer and a default PaymentSource:
```elixir
customer_attrs =
  %{
    name: " ",
    email: "an@email.com",
    payment_sources: [
      %{
        token_id: "tok_test_visa_4242",
        type: "card",
      }
    ]
  }
{:ok, customer} = ConektaEx.Customer.create(customer_attrs)

order_attrs =
  %{
    amount: 2000,
    charges: [
      %{payment_method: %{type: "default"}}
    ],
    currency: "MXN",
    customer_info: %{
      customer_id: customer.id
    },
    line_items: [
      %{
        name: "some name",
        quantity: 2000,
        unit_price: 1,
      }
    ]
  }
{:ok, order} = ConektaEx.Order.create(order_attrs)
```

Payment without a Customer (this DOES NOT create a Customer):
```elixir
order_attrs =
  %{
    amount: 2000,
    charges: [
      %{
        payment_method: %{
          type: "card",
          token_id: "tok_test_visa_4242"
        }
      }
    ],
    currency: "MXN",
    customer_info: %{
      name: " ",
      phone: "1234567890",
      email: "an@email.com"
    },
    line_items: [
      %{
        name: "some name",
        quantity: 2000,
        unit_price: 1,
      }
    ]
  }
{:ok, order} = ConektaEx.Order.create(order_attrs)
```

### Customer fn's
#### CRUD
```elixir
customer_attrs = %{name: " ", email: "an@email.com"}
{:ok, c_customer} = ConektaEx.Customer.create(customer_attrs)
{:ok, u_customer} = ConektaEx.Customer.update(c_customer.id, %{name: "name"})
{:ok, %{name: "name"} = customer} = ConektaEx.Customer.retrieve(u_customer.id)
{:ok, %{name: "name"}} = ConektaEx.Customer.delete(customer.id)
```
#### Payment Sources (Cards)
```elixir
{:ok, ps} = ConektaEx.Customer.create_payment_source(customer_id, "card", "tok_test_visa_4242")
{:ok, %{name: "new name"} = ps} = ConektaEx.Customer.update_payment_source(customer_id, ps.id, %{name: "new name"})
{:ok, %{name: "new name"}} = ConektaEx.Customer.delete_payment_source(customer_id, ps.id)
```

### Subscriptions
#### Create
```elixir
plan_attrs =
  %{
    id: "a-id",
    name: "a name",
    amount: 2000,
    currency: "MXN",
    interval: "month"
  }
{:ok, plan} = ConektaEx.Plan.create(plan_attrs)
{:ok, sub} = ConektaEx.Customer.create_subscription(customer_id, subscription_id, plan.id)
# wait and handle subscription Webhook
```
#### Pause / Resume / Cancel
```elixir
{:ok, sub} = ConektaEx.Customer.pause_subscription(customer_id, subscription_id)
{:ok, sub} = ConektaEx.Customer.resume_subscription(customer_id, subscription_id)
{:ok, sub} = ConektaEx.Customer.cancel_subscription(customer_id, subscription_id)
```

### Pagination
Conekta uses a Struct to represent List of Objects, which i named StructList :v,
i found some endpoints that the api docs doesn't have, like, `/customers`,
`/orders`, `/plans`, So if you need to list those use ConektaEx.STRUCT.list, and
ConektaEx.STRUCT.next_page and ConektaEx.STRUCT.previous_page.

```elixir
{:ok, %StructList{}} = ConektaEx.Customer.list()
{:ok, %StructList{}} = ConektaEx.Plan.list()
{:ok, %StructList{}} = ConektaEx.Order.list()
```

Other endpoints unlisted in the api docs without list/next/previous function (PR's are welcome):
`/customers/:id/payment_sources`, `/orders/:id/charges`,
`/orders/:id/line_items`, `/orders/:id/shipping_lines`,
`/customers/:id/shipping_contacts`, `/orders/:id/discount_lines`,
`/orders/:id/tax_lines`.

### Webhooks
When using webhooks, you will have to handle different event `type`s.
```elixir
{:ok, event} = ConektaEx.Event.decode(json)
case Map.get(event, :type) do
  "charge.paid" ->
    do_something(:charge_paid, event)

  "charge.refunded" ->
    do_something(:charge_refunded, event)

  "subscription.paid" ->
    do_something(:subscription_paid, event)

  "subscription.payment_failed" ->
    do_something(:subscription_payment_failed, event)
end
```