Packages

A production-grade, fully-typed Elixir client for the SumUp API (Checkouts, Readers, Customers, Transactions, Payouts, Receipts, Members, Memberships, Roles and Merchants) with telemetry, retries, cursor streaming, webhook handling, and RFC 9457 aware error handling.

Current section

Files

Jump to
sumup lib sumup money.ex
Raw

lib/sumup/money.ex

defmodule Sumup.Money do
@moduledoc """
SumUp represents money in two different, incompatible shapes depending on
which API generation you're calling:
* `Sumup.Money.Float` — legacy major-unit float + currency, used by
Checkouts, Customers, Transactions and Payouts.
* `Sumup.Money.MinorUnit` — integer minor units + explicit exponent +
currency, used by Readers.
This module intentionally does **not** unify them into one struct: doing
so would either lose precision (coercing minor units to float) or require
guessing a currency's exponent (coercing float to minor units). Instead,
each resource module returns whichever shape the underlying endpoint
actually returns, and this module offers currency metadata shared by
both.
"""
@zero_decimal_currencies ~w(BIF CLP DJF GNF ISK JPY KMF KRW PYG RWF UGX
UYI VND VUV XAF XOF XPF HUF)
@doc """
Returns the ISO 4217 decimal exponent for a currency code, defaulting to
`2` for anything not explicitly known.
Useful for converting `Sumup.Money.Float` amounts to minor units, since
legacy endpoints don't send the exponent explicitly.
iex> Sumup.Money.exponent_for("JPY")
0
iex> Sumup.Money.exponent_for("EUR")
2
"""
@spec exponent_for(String.t()) :: non_neg_integer()
def exponent_for(currency) when is_binary(currency) do
if String.upcase(currency) in @zero_decimal_currencies, do: 0, else: 2
end
@doc "Returns true if `currency` has no minor unit (e.g. JPY, KRW)."
@spec zero_decimal?(String.t()) :: boolean()
def zero_decimal?(currency), do: exponent_for(currency) == 0
end