Current section
Files
Jump to
Current section
Files
lib/adapters/payment_gateway.ex
defmodule Bold.Adapters.PaymentGateway do
@moduledoc """
HTTP client to communicate with the Bold API.
"""
use Tesla
alias Bold.Config
alias Bold.Types.{
Error,
PaymentLinkRequest,
PaymentLinkResponse,
PaymentMethodsResponse,
PaymentStatusResponse
}
@behaviour Bold.Ports.PaymentGateway
plug(Tesla.Middleware.BaseUrl, Config.api_url())
plug(Tesla.Middleware.Headers, [
{"Content-Type", "application/json"},
{"Authorization", "x-api-key #{Config.api_key()}"}
])
plug(Tesla.Middleware.JSON)
@url "/online/link/v1"
@impl true
@spec create_link(PaymentLinkRequest.t()) ::
{:ok, PaymentLinkResponse.t()} | {:errors, list(Error.t())}
def create_link(params) when is_map(params) do
@url
|> post(link_request(params))
|> link_response()
end
@impl true
@spec get_link(String.t()) :: {:ok, PaymentStatusResponse.t()} | {:errors, list(Error.t())}
def get_link(id) when is_binary(id) do
"#{@url}/#{id}"
|> get()
|> status_response()
end
@impl true
@spec list_methods() :: {:ok, PaymentMethodsResponse.t()} | {:errors, list(Error.t())}
def list_methods do
"#{@url}/payment_methods"
|> get()
|> methods_response()
end
@spec link_request(PaymentLinkRequest.t()) :: map()
defp link_request(%PaymentLinkRequest{} = request) do
amount_type = Map.get(request, :amount_type)
amount = Map.get(request, :amount)
description = Map.get(request, :description)
expiration_date = Map.get(request, :expiration_date)
callback_url = Map.get(request, :callback_url)
payment_methods = Map.get(request, :payment_methods)
payer_email = Map.get(request, :payer_email)
image_url = Map.get(request, :image_url)
amount_type =
case amount_type do
:close -> "CLOSE"
_ -> "OPEN"
end
%{
amount_type: amount_type,
amount: amount,
description: description,
expiration_date: expiration_date,
callback_url: callback_url,
payment_methods: payment_methods,
payer_email: payer_email,
image_url: image_url
}
end
defp link_request(_), do: %{}
@spec link_response({:ok, Tesla.Env.t()}) ::
{:ok, PaymentLinkResponse.t()} | {:errors, list(Error.t())}
defp link_response({:ok, %Tesla.Env{status: 200, body: %{"payload" => body}}}) do
link = %PaymentLinkResponse{payment_link: body["payment_link"], url: body["url"]}
{:ok, link}
end
defp link_response({:ok, %Tesla.Env{status: _code, body: %{"errors" => errors}}}) do
{:errors, errors}
end
defp link_response({:ok, %Tesla.Env{status: _code, body: reason}}) do
{:errors, [reason]}
end
defp link_response({:error, reason}) do
{:errors, IO.inspect(reason)}
end
@spec status_response({:ok, Tesla.Env.t()} | {:error, Tesla.Env.t()}) ::
{:ok, PaymentStatusResponse.t()} | {:error, list(Error.t())}
defp status_response({:ok, %Tesla.Env{status: 200, body: body}}) do
amount_type =
case body["amount_type"] do
"OPEN" -> :open
_ -> :close
end
status =
case body["status"] do
"ACTIVE" -> :active
"PROCESSING" -> :processing
"PAID" -> :paid
"REJECTED" -> :rejected
"CANCELLED" -> :cancelled
"EXPIRED" -> :expired
end
status = %PaymentStatusResponse{
api_version: body["api_version"],
id: body["id"],
total: body["total"],
subtotal: body["subtotal"],
tip_amount: body["tip_amount"],
taxes: body["taxes"],
status: status,
expiration_date: body["expiration_date"],
creation_date: body["creation_date"],
description: body["description"],
payment_method: body["payment_method"],
transaction_id: body["transaction_id"],
amount_type: amount_type,
is_sandbox: body["is_sandbox"]
}
{:ok, status}
end
defp status_response({:ok, %Tesla.Env{status: _code, body: %{"errors" => errors}}}) do
{:errors, errors}
end
defp status_response({:error, reason}) do
{:errors, [reason]}
end
@spec methods_response({:ok, Tesla.Env.t()} | {:error, Tesla.Env.t()}) ::
{:ok, PaymentMethodsResponse.t()} | {:error, list(Error.t())}
defp methods_response({:ok, %Tesla.Env{status: 200, body: %{"payload" => body}}}) do
methods = %PaymentMethodsResponse{
list: body["payment_methods"]
}
{:ok, methods}
end
defp methods_response({:ok, %Tesla.Env{status: _code, body: %{"errors" => errors}}}) do
{:errors, errors}
end
defp methods_response({:ok, _}) do
{:errors, [:request_failed]}
end
defp methods_response({:error, reason}) do
{:errors, [reason]}
end
end