Packages
phoenix_kit
1.7.11
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit/billing/currency.ex
defmodule PhoenixKit.Billing.Currency do
@moduledoc """
Currency schema for PhoenixKit Billing system.
Manages supported currencies with exchange rates for multi-currency billing.
## Schema Fields
- `code`: ISO 4217 currency code (e.g., "EUR", "USD", "GBP")
- `name`: Full currency name (e.g., "Euro", "US Dollar")
- `symbol`: Currency symbol (e.g., "€", "$", "£")
- `decimal_places`: Number of decimal places (usually 2)
- `is_default`: Whether this is the default currency
- `enabled`: Whether currency is available for use
- `exchange_rate`: Rate relative to base currency
- `sort_order`: Display order in currency lists
## Usage Examples
# List all enabled currencies
currencies = PhoenixKit.Billing.list_currencies()
# Get default currency
currency = PhoenixKit.Billing.get_default_currency()
# Format amount in currency
PhoenixKit.Billing.Currency.format_amount(99.99, currency)
# => "€99.99"
"""
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query, warn: false
@primary_key {:id, :id, autogenerate: true}
schema "phoenix_kit_currencies" do
field :code, :string
field :name, :string
field :symbol, :string
field :decimal_places, :integer, default: 2
field :is_default, :boolean, default: false
field :enabled, :boolean, default: true
field :exchange_rate, :decimal, default: Decimal.new("1.0")
field :sort_order, :integer, default: 0
timestamps(type: :utc_datetime_usec)
end
@doc """
Creates a changeset for currency creation and updates.
"""
def changeset(currency, attrs) do
currency
|> cast(attrs, [
:code,
:name,
:symbol,
:decimal_places,
:is_default,
:enabled,
:exchange_rate,
:sort_order
])
|> validate_required([:code, :name, :symbol])
|> validate_length(:code, is: 3)
|> validate_length(:symbol, min: 1, max: 5)
|> validate_number(:decimal_places, greater_than_or_equal_to: 0, less_than_or_equal_to: 4)
|> validate_number(:exchange_rate, greater_than: 0)
|> unique_constraint(:code)
|> upcase_code()
end
defp upcase_code(changeset) do
case get_change(changeset, :code) do
nil -> changeset
code -> put_change(changeset, :code, String.upcase(code))
end
end
@doc """
Formats an amount with currency symbol.
## Examples
iex> currency = %Currency{symbol: "€", decimal_places: 2}
iex> Currency.format_amount(Decimal.new("99.99"), currency)
"€99.99"
iex> Currency.format_amount(1234.5, currency)
"€1,234.50"
"""
def format_amount(amount, %__MODULE__{symbol: symbol, decimal_places: places}) do
amount
|> to_decimal()
|> Decimal.round(places)
|> format_with_thousands()
|> then(&"#{symbol}#{&1}")
end
@doc """
Formats an amount without currency symbol.
"""
def format_amount_plain(amount, %__MODULE__{decimal_places: places}) do
amount
|> to_decimal()
|> Decimal.round(places)
|> format_with_thousands()
end
defp to_decimal(%Decimal{} = d), do: d
defp to_decimal(n) when is_number(n), do: Decimal.from_float(n * 1.0)
defp to_decimal(s) when is_binary(s), do: Decimal.new(s)
defp format_with_thousands(decimal) do
decimal
|> Decimal.to_string(:normal)
|> String.split(".")
|> case do
[integer] ->
format_integer_part(integer)
[integer, fraction] ->
"#{format_integer_part(integer)}.#{fraction}"
end
end
defp format_integer_part(str) do
str
|> String.reverse()
|> String.graphemes()
|> Enum.chunk_every(3)
|> Enum.join(",")
|> String.reverse()
end
@doc """
Converts amount from one currency to another.
## Examples
iex> from = %Currency{exchange_rate: Decimal.new("1.0")} # EUR (base)
iex> to = %Currency{exchange_rate: Decimal.new("1.1")} # USD
iex> Currency.convert(100, from, to)
Decimal.new("110.00")
"""
def convert(amount, %__MODULE__{exchange_rate: from_rate}, %__MODULE__{exchange_rate: to_rate}) do
amount
|> to_decimal()
|> Decimal.div(from_rate)
|> Decimal.mult(to_rate)
|> Decimal.round(2)
end
end