Packages

A complete, production-grade Elixir client for the Monzo API: OAuth2, Accounts, Balance, Pots, Transactions, Feed Items, Attachments, Transaction Receipts, and Webhooks. Zero required dependencies.

Current section

Files

Jump to
monzo_client lib monzo pots.ex
Raw

lib/monzo/pots.ex

defmodule Monzo.Pots do
@moduledoc "The Pots resource: listing pots and moving money into/out of them."
alias Monzo.Client
alias Monzo.Error.ValidationError
alias Monzo.HTTP
alias Monzo.Internal.Path
alias Monzo.Pot
@type transfer_params :: %{
required(:pot_id) => String.t(),
required(:amount) => integer(),
required(:dedupe_id) => String.t()
}
@doc """
Returns a list of pots owned by the currently authorised user for the
given current account.
"""
@spec list(Client.t(), String.t()) :: {:ok, [Pot.t()]} | {:error, Exception.t()}
def list(%Client{} = client, current_account_id) do
request =
HTTP.request(client,
method: :get,
path: "/pots",
query: %{"current_account_id" => current_account_id}
)
with {:ok, %{"pots" => pots}} <- request do
{:ok, Enum.map(pots, &Pot.from_json/1)}
end
end
@doc """
Moves money from an account into a pot.
`:dedupe_id` must remain static across retries of the *same* logical
deposit to prevent Monzo from double-processing it; generate a new one
for each new deposit.
"""
@spec deposit(Client.t(), transfer_params() | %{source_account_id: String.t()}) ::
{:ok, Pot.t()} | {:error, Exception.t()}
def deposit(%Client{} = client, %{
pot_id: pot_id,
amount: amount,
dedupe_id: dedupe_id,
source_account_id: source_account_id
}) do
with :ok <- validate_transfer(pot_id, amount, dedupe_id),
:ok <- validate_present(:source_account_id, source_account_id) do
request =
HTTP.request(client,
method: :put,
path: "/pots/#{Path.encode_segment(pot_id)}/deposit",
encoding: :form,
form: %{
"source_account_id" => source_account_id,
"amount" => amount,
"dedupe_id" => dedupe_id
}
)
with {:ok, json} <- request, do: {:ok, Pot.from_json(json)}
end
end
@doc """
Moves money from a pot into an account.
`:dedupe_id` must remain static across retries of the *same* logical
withdrawal to prevent Monzo from double-processing it.
"""
@spec withdraw(Client.t(), transfer_params() | %{destination_account_id: String.t()}) ::
{:ok, Pot.t()} | {:error, Exception.t()}
def withdraw(%Client{} = client, %{
pot_id: pot_id,
amount: amount,
dedupe_id: dedupe_id,
destination_account_id: destination_account_id
}) do
with :ok <- validate_transfer(pot_id, amount, dedupe_id),
:ok <- validate_present(:destination_account_id, destination_account_id) do
request =
HTTP.request(client,
method: :put,
path: "/pots/#{Path.encode_segment(pot_id)}/withdraw",
encoding: :form,
form: %{
"destination_account_id" => destination_account_id,
"amount" => amount,
"dedupe_id" => dedupe_id
}
)
with {:ok, json} <- request, do: {:ok, Pot.from_json(json)}
end
end
defp validate_transfer(pot_id, amount, dedupe_id) do
with :ok <- validate_present(:pot_id, pot_id),
:ok <- validate_positive_integer(:amount, amount) do
validate_present(:dedupe_id, dedupe_id)
end
end
defp validate_present(_field, value) when is_binary(value) and value != "", do: :ok
defp validate_present(field, _value),
do: {:error, %ValidationError{field: field, message: "must not be empty"}}
defp validate_positive_integer(_field, value) when is_integer(value) and value > 0, do: :ok
defp validate_positive_integer(field, _value) do
{:error,
%ValidationError{field: field, message: "must be a positive integer number of minor units"}}
end
end