Ex_money: casting JSON to Money is not respecting decimal point

Why do I see different behavior here?

While doing the cast in IEX I see the expected result:

iex [17:06 :: 22] > %{"amount" => "1.5", "currency" => "EUR"} |> Money.Ecto.Composite.Type.cast()
{:ok, Money.new(:EUR, "1.5")}

the application is somehow respecting the locale setting (which is “de” in the case and “.” is not a comma delimiter but “,” is):

  Map.get(params, "balance") #=> "{\"currency\":\"EUR\",\"amount\":\"1.00\"}"
|> Jason.decode!() #=> %{"amount" => "1.00", "currency" => "EUR"}
|> Money.Ecto.Composite.Type.cast() #=> {:ok, Money.new(:EUR, "100")}

Thus getting back a Money value multiplied by 100

One might set the default locale in custom Cldr module as

defmodule MyApp.Cldr do
  use Cldr, locales: ["en", "fr", "de"], default_locale: "en"
end

or explicitly pass the locale in a call to cast/2 (no idea why it’s not documented, a PR documenting it would be appreciated, I believe.)

iex|🌢|1 ▶ %{"amount" => "1.00", "currency" => "EUR"}
          |> Money.Ecto.Composite.Type.cast(locale: :de)
{:ok, Money.new(:EUR, "100")}
iex|🌢|2 ▶ %{"amount" => "1.00", "currency" => "EUR"}
          |> Money.Ecto.Composite.Type.cast(locale: :en)
{:ok, Money.new(:EUR, "1.00")}
1 Like

Yeah, the issue here is that cast expects human format (formatted to the locale rules of the user), not machine format. If you need the later you need to make sure the decoding happens using the correct locale.

@mudasobwa @LostKobrakai
Thanks a lot.
Checked the documentation for cast more carefully
I did not know that cast has a locale option

Typically I don’t document behaviour implementations, but I agree that in this case its important to understand the behaviour (no pun intended) of Money.Ecto.Composite.Type.cast/2.

I’ve published documentation for Money.Ecto.Composite.Type.cast/2 and would welcome any PRs that improve it.

3 Likes