Skip to content

Commit ddae0e8

Browse files
committed
ISO4217 codes take precendence of digital tokens. Closes #190
1 parent 2e1afe3 commit ddae0e8

File tree

8 files changed

+65
-30
lines changed

8 files changed

+65
-30
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@
22

33
**Note** `ex_money` 5.17.0 and later is supported on Elixir 1.12 and later versions only.
44

5-
## Money v5.24.0
5+
## Money v5.24.1
6+
7+
This is the changelog for Money v5.24.1 released on January 20th, 2026. For older changelogs please consult the release tag on [GitHub](https://github.com/kipcole9/money/tags)
8+
9+
### Bug Fixes
10+
11+
* Fixes casting a binary currency code that is both a valid ISO4217 currency code and a valid digital currency short code (for example, "TRY"). Precedence is given to returning the ISO4217 code (this was not the case in v5.24.0).
12+
13+
## Money v5.24.0 (deprecated and retired)
614

715
This is the changelog for Money v5.24.0 released on January 18th, 2026. For older changelogs please consult the release tag on [GitHub](https://github.com/kipcole9/money/tags)
816

lib/money.ex

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ defmodule Money do
171171
Money.new(:EUR, "100.30", fractional_digits: 4)
172172
173173
iex> Money.new(:XYZZ, 100)
174-
{:error, {Money.UnknownCurrencyError, "The currency :XYZZ is invalid"}}
174+
{:error, {Money.UnknownCurrencyError, "The currency :XYZZ is unknown"}}
175175
176176
iex> Money.new("1.000,99", :EUR, locale: "de")
177177
Money.new(:EUR, "1000.99")
@@ -2375,7 +2375,7 @@ defmodule Money do
23752375
23762376
iex> Money.to_currency(Money.new(:USD, 100), :AUDD,
23772377
...> %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)})
2378-
{:error, {Cldr.UnknownCurrencyError, "The currency :AUDD is invalid"}}
2378+
{:error, {Cldr.UnknownCurrencyError, "The currency :AUDD is unknown"}}
23792379
23802380
iex> Money.to_currency(Money.new(:USD, 100), :CHF,
23812381
...> %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)})
@@ -2793,7 +2793,7 @@ defmodule Money do
27932793
Money.new(:USD, "0")
27942794
27952795
iex> Money.zero :ZZZ
2796-
{:error, {Cldr.UnknownCurrencyError, "The currency :ZZZ is invalid"}}
2796+
{:error, {Cldr.UnknownCurrencyError, "The currency :ZZZ is unknown"}}
27972797
27982798
"""
27992799
@spec zero(Currency.currency_reference() | Money.t()) :: Money.t() | {:error, {module(), binary()}}
@@ -2951,9 +2951,19 @@ defmodule Money do
29512951

29522952
@doc false
29532953
def validate_currency(currency_code) do
2954+
case Cldr.Currency.validate_currency(currency_code) do
2955+
{:ok, currency_code} -> {:ok, currency_code}
2956+
{:error, error} -> validate_digital_token(currency_code, error)
2957+
end
2958+
end
2959+
2960+
defp validate_digital_token(currency_code, original_error) do
29542961
case DigitalToken.validate_token(currency_code) do
2955-
{:ok, token_id} -> {:ok, token_id}
2956-
{:error, _} -> Cldr.Currency.validate_currency(currency_code)
2962+
{:ok, token_id} ->
2963+
{:ok, token_id}
2964+
2965+
{:error, {DigitalToken.UnknownTokenError, _}} ->
2966+
{:error, original_error}
29572967
end
29582968
end
29592969

lib/money/backend.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ defmodule Money.Backend do
8585
Money.new(:EUR, "100.30")
8686
8787
iex> #{inspect(__MODULE__)}.new(:XYZZ, 100)
88-
{:error, {Money.UnknownCurrencyError, "The currency :XYZZ is invalid"}}
88+
{:error, {Money.UnknownCurrencyError, "The currency :XYZZ is unknown"}}
8989
9090
iex> #{inspect(__MODULE__)}.new("1.000,99", :EUR, locale: "de")
9191
Money.new(:EUR, "1000.99")
@@ -1015,7 +1015,7 @@ defmodule Money.Backend do
10151015
{:ok, Money.new(:AUD, "73.4500")}
10161016
10171017
iex> #{inspect(__MODULE__)}.to_currency Money.new(:USD, 100), :AUDD, %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)}
1018-
{:error, {Cldr.UnknownCurrencyError, "The currency :AUDD is invalid"}}
1018+
{:error, {Cldr.UnknownCurrencyError, "The currency :AUDD is unknown"}}
10191019
10201020
iex> #{inspect(__MODULE__)}.to_currency Money.new(:USD, 100), :CHF, %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)}
10211021
{:error, {Money.ExchangeRateError, "No exchange rate is available for currency :CHF"}}
@@ -1283,7 +1283,7 @@ defmodule Money.Backend do
12831283
Money.new(:USD, "0")
12841284
12851285
iex> #{inspect(__MODULE__)}.zero :ZZZ
1286-
{:error, {Cldr.UnknownCurrencyError, "The currency :ZZZ is invalid"}}
1286+
{:error, {Cldr.UnknownCurrencyError, "The currency :ZZZ is unknown"}}
12871287
12881288
"""
12891289
@spec zero(Currency.currency_reference() | Money.t()) :: Money.t() | {:error, {module(), binary()}}

lib/money/exception.ex

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ defmodule Money.UnknownCurrencyError do
66
end
77
end
88

9+
defmodule Money.InvalidCurrencyError do
10+
defexception [:message]
11+
12+
def exception(message) do
13+
%__MODULE__{message: message}
14+
end
15+
end
16+
917
defmodule Money.FormatError do
1018
defexception [:message]
1119

mix.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Money.Mixfile do
22
use Mix.Project
33

4-
@version "5.24.0"
4+
@version "5.24.1"
55

66
def project do
77
[
@@ -91,6 +91,7 @@ defmodule Money.Mixfile do
9191

9292
defp deps do
9393
[
94+
{:ex_cldr, "~> 2.46"},
9495
{:ex_cldr_numbers, "~> 2.38"},
9596

9697
# Used for Money.Subscription.Plan.to_string/1

mix.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
"elixir_xml_to_map": {:hex, :elixir_xml_to_map, "3.1.0", "4d6260486a8cce59e4bf3575fe2dd2a24766546ceeef9f93fcec6f7c62a2827a", [:mix], [{:erlsom, "~> 1.4", [hex: :erlsom, repo: "hexpm", optional: false]}], "hexpm", "8fe5f2e75f90bab07ee2161120c2dc038ebcae8135554f5582990f1c8c21f911"},
1212
"erlex": {:hex, :erlex, "0.2.8", "cd8116f20f3c0afe376d1e8d1f0ae2452337729f68be016ea544a72f767d9c12", [:mix], [], "hexpm", "9d66ff9fedf69e49dc3fd12831e12a8a37b76f8651dd21cd45fcf5561a8a7590"},
1313
"erlsom": {:hex, :erlsom, "1.5.2", "3e47c53a199136fb4d20d5479edb7c9229f31624534c062633951c8d14dcd276", [:rebar3], [], "hexpm", "4e765cc677fb30509f7b628ff2914e124cf4dcc0fac1c0a62ee4dcee24215b5d"},
14-
"ex_cldr": {:hex, :ex_cldr, "2.45.1", "e03794a96cecba6a75b0cf409fcf89a40ceadce15a13f8572394c64ee22d1971", [:mix], [{:cldr_utils, "~> 2.28", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19 or ~> 1.0", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "32498af496be50d2c94a32166cde7227b3ce54d0e62be783f7445469140cdb26"},
14+
"ex_cldr": {:hex, :ex_cldr, "2.46.0", "29b5bb638932ca4fc4339595145e327b797f59963a398c12a6aee1efe5a35b1b", [:mix], [{:cldr_utils, "~> 2.28", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19 or ~> 1.0", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "14157ac16694e99c1339ac25a4f10d3df0e0d15cc1a35073b37e195487c1b6cb"},
1515
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.17.0", "c38d76339dbee413f7dd1aba4cdf05758bd4c0bbfe9c3b1c8602f96082c2890a", [:mix], [{:ex_cldr, "~> 2.38", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "9af59bd29407dcca59fa39ded8c1649ae1cf6ec29fd0611576dcad0279bce0db"},
1616
"ex_cldr_lists": {:hex, :ex_cldr_lists, "2.11.1", "ad18f861d7c5ca82aac6d173469c6a2339645c96790172ab0aa255b64fb7303b", [:mix], [{:ex_cldr_numbers, "~> 2.25", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "00161c04510ccb3f18b19a6b8562e50c21f1e9c15b8ff4c934bea5aad0b4ade2"},
1717
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.38.0", "b5564b57d3769c85e16689472a9bb65804f71ccd3484144e31998398fda25ad1", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.45", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.17", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "b29e4d723c69db5d0a3f3bcef7583a0bc87dda1cd642187c589fec4bfc59a703"},
1818
"ex_cldr_units": {:hex, :ex_cldr_units, "3.20.1", "b27ec81814a67ed77d1c06c64ef74519b141497b74244ec18e1a1a2f78f8e313", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.36", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "879af22563b06570f16c28bed3decaadc0c1233906f4516b2d5d28e2bbbadee0"},
19-
"ex_doc": {:hex, :ex_doc, "0.39.3", "519c6bc7e84a2918b737aec7ef48b96aa4698342927d080437f61395d361dcee", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "0590955cf7ad3b625780ee1c1ea627c28a78948c6c0a9b0322bd976a079996e1"},
19+
"ex_doc": {:hex, :ex_doc, "0.40.0", "2635974389b80fd3ca61b0f993d459dad05b4a8f9b069dcfbbc5f6a8a6aef60e", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "c040735250e2752b6e1102eeb4aa3f1dca74c316db873ae09f955d42136e7e5b"},
2020
"expo": {:hex, :expo, "1.1.1", "4202e1d2ca6e2b3b63e02f69cfe0a404f77702b041d02b58597c00992b601db5", [:mix], [], "hexpm", "5fb308b9cb359ae200b7e23d37c76978673aa1b06e2b3075d814ce12c5811640"},
2121
"exprintf": {:hex, :exprintf, "0.2.1", "b7e895dfb00520cfb7fc1671303b63b37dc3897c59be7cbf1ae62f766a8a0314", [:mix], [], "hexpm", "20a0e8c880be90e56a77fcc82533c5d60c643915c7ce0cc8aa1e06ed6001da28"},
2222
"exprof": {:hex, :exprof, "0.2.4", "13ddc0575a6d24b52e7c6809d2a46e9ad63a4dd179628698cdbb6c1f6e497c98", [:mix], [{:exprintf, "~> 0.2", [hex: :exprintf, repo: "hexpm", optional: false]}], "hexpm", "0884bcb66afc421c75d749156acbb99034cc7db6d3b116c32e36f32551106957"},

test/money_exchange_rates_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ defmodule Money.ExchangeRates.Test do
3030
test "Convert from USD to ZZZ should return an error" do
3131
capture_io(fn ->
3232
assert Money.to_currency(Money.new(:USD, 100), :ZZZ) ==
33-
{:error, {Cldr.UnknownCurrencyError, "The currency :ZZZ is invalid"}}
33+
{:error, {Cldr.UnknownCurrencyError, "The currency :ZZZ is unknown"}}
3434
end)
3535
end
3636

3737
test "Convert from USD to ZZZ should raise an exception" do
3838
capture_io(fn ->
39-
assert_raise Cldr.UnknownCurrencyError, ~r/The currency :ZZZ is invalid/, fn ->
39+
assert_raise Cldr.UnknownCurrencyError, ~r/The currency :ZZZ is unknown/, fn ->
4040
assert Money.to_currency!(Money.new(:USD, 100), :ZZZ)
4141
end
4242
end)

test/money_test.exs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ defmodule MoneyTest do
3434

3535
test "create a new money struct wth a invalid binary currency code and binary amount" do
3636
money = Money.new("1234", "ZZZ")
37-
assert money == {:error, {Money.UnknownCurrencyError, "The currency \"ZZZ\" is invalid"}}
37+
assert money == {:error, {Money.UnknownCurrencyError, "The currency \"ZZZ\" is unknown"}}
3838

3939
money = Money.new("ZZZ", "1234")
40-
assert money == {:error, {Money.UnknownCurrencyError, "The currency \"ZZZ\" is invalid"}}
40+
assert money == {:error, {Money.UnknownCurrencyError, "The currency \"ZZZ\" is unknown"}}
4141
end
4242

4343
test "create a new! money struct with a binary currency code" do
@@ -154,15 +154,15 @@ defmodule MoneyTest do
154154
end
155155

156156
test "raise when creating a new money struct from invalid input" do
157-
assert_raise Money.UnknownCurrencyError, "The currency \"ABCDE\" is invalid", fn ->
157+
assert_raise Money.UnknownCurrencyError, "The currency \"ABCDE\" is unknown", fn ->
158158
Money.new!("ABCDE", 100)
159159
end
160160

161-
assert_raise Money.UnknownCurrencyError, "The currency \"ABCDE\" is invalid", fn ->
161+
assert_raise Money.UnknownCurrencyError, "The currency \"ABCDE\" is unknown", fn ->
162162
Money.new!(Decimal.new(100), "ABCDE")
163163
end
164164

165-
assert_raise Money.UnknownCurrencyError, "The currency \"ABCDE\" is invalid", fn ->
165+
assert_raise Money.UnknownCurrencyError, "The currency \"ABCDE\" is unknown", fn ->
166166
Money.new!("ABCDE", Decimal.new(100))
167167
end
168168
end
@@ -187,12 +187,20 @@ defmodule MoneyTest do
187187

188188
test "creating a money struct with an invalid atom currency code returns error tuple" do
189189
assert Money.new(:ZYZ, 100) ==
190-
{:error, {Money.UnknownCurrencyError, "The currency :ZYZ is invalid"}}
190+
{:error, {Money.UnknownCurrencyError, "The currency :ZYZ is unknown"}}
191191
end
192192

193193
test "creating a money struct with an invalid binary currency code returns error tuple" do
194194
assert Money.new("XYZABC", 100) ==
195-
{:error, {Money.UnknownCurrencyError, "The currency \"XYZABC\" is invalid"}}
195+
{:error, {Money.UnknownCurrencyError, "The currency \"XYZABC\" is unknown"}}
196+
end
197+
198+
test "creating a money struct with a code that is also a digital token short code" do
199+
money = Money.new(:TRY, 100)
200+
assert :TRY = money.currency
201+
202+
money = Money.new("TRY", 100)
203+
assert :TRY = money.currency
196204
end
197205

198206
test "string output of money is correctly formatted" do
@@ -206,13 +214,13 @@ defmodule MoneyTest do
206214
end
207215

208216
# Comment out until the next version that depends on ex_cldr_numbers 2.31.0
209-
# test "to_string! raises if there is an error" do
210-
# money = Money.new(1234, :USD)
211-
#
212-
# assert_raise Cldr.FormatCompileError, fn ->
213-
# Money.to_string!(money, format: "0#")
214-
# end
215-
# end
217+
test "to_string! raises if there is an error" do
218+
money = Money.new(1234, :USD)
219+
220+
assert_raise Cldr.FormatCompileError, fn ->
221+
Money.to_string!(money, format: "0#")
222+
end
223+
end
216224

217225
test "abs value of a negative value returns positive value" do
218226
assert Money.abs(Money.new(:USD, -100)) == Money.new(:USD, 100)
@@ -454,15 +462,15 @@ defmodule MoneyTest do
454462
end
455463

456464
test "raise when a sigil function has an invalid currency" do
457-
assert_raise Money.UnknownCurrencyError, ~r/The currency .* is invalid/, fn ->
465+
assert_raise Money.UnknownCurrencyError, ~r/The currency .* is unknown/, fn ->
458466
Money.Sigil.sigil_M("42", [?A, ?A, ?A])
459467
end
460468
end
461469

462470
test "raise when a sigil has an invalid currency" do
463471
import Money.Sigil
464472

465-
assert_raise Money.UnknownCurrencyError, ~r/The currency .* is invalid/, fn ->
473+
assert_raise Money.UnknownCurrencyError, ~r/The currency .* is unknown/, fn ->
466474
~M[42]ABD
467475
end
468476
end

0 commit comments

Comments
 (0)