Repository: elixirmoney/money (elixir)

Issue:
Money.parse doesn't handle scientific notation
I consider this a bug in our code, but I wanted to document it here, just so people are aware.

We had some code where Decimals were being represented in scientific notation, e.g.

```elixir
value = Decimal.new("0")
divisor = :math.pow(10, 2) |> Decimal.from_float() # Decimal.new("100.0")
value = Decimal.div(value, divisor) # Decimal.new("0E+1")
```

That itself isn't a problem. The problem happens with some Money.parse code like this:

```elixir
Money.parse!("#{value}", currency)
```

Which is effectively doing this:

```elixir
Money.parse!("0E+1", :USD) # %Money{amount: 100, currency: :USD}
```

So converting to a string before parsing Money is resulting in $1 when the original input was 0, or more specifically 0E+1.

Passing the Decimal directly to Money works just fine.

```elixir
Decimal.new("0E+1") |> Money.parse!(:USD) # %Money{amount: 0, currency: :USD}
```

I'm not sure if this should be "fixed" -- is Money supposed to be able to parse scientific notation? Maybe it just needs to be called out as not supported?

Pull request description:
feat: add support parsing scientific notation
Resolves #216 

Patch:
diff --git a/lib/money.ex b/lib/money.ex
index 9172381..55e9a80 100644
--- a/lib/money.ex
+++ b/lib/money.ex
@@ -210,6 +210,15 @@ defmodule Money do
   defp prepare_parse_string(["9" | tail], delimiter, acc),
     do: prepare_parse_string(tail, delimiter, ["9" | acc])
 
+  defp prepare_parse_string(["e" | tail], delimiter, acc),
+    do: prepare_parse_string(tail, delimiter, ["e" | acc])
+
+  defp prepare_parse_string(["E" | tail], delimiter, acc),
+    do: prepare_parse_string(tail, delimiter, ["e" | acc])
+
+  defp prepare_parse_string(["+" | tail], delimiter, acc),
+    do: prepare_parse_string(tail, delimiter, ["+" | acc])
+
   defp prepare_parse_string([delimiter | tail], delimiter, acc),
     do: prepare_parse_string(tail, delimiter, ["." | acc])
 


Test patch:
diff --git a/test/money_test.exs b/test/money_test.exs
index dc66717..b64296c 100644
--- a/test/money_test.exs
+++ b/test/money_test.exs
@@ -50,6 +50,15 @@ defmodule MoneyTest do
     assert Money.parse(",25", :EUR, separator: ".", delimiter: ",") == {:ok, eur(25)}
     assert Money.parse("-,25", :EUR, separator: ".", delimiter: ",") == {:ok, eur(-25)}
 
+    assert Money.parse("0E+1", :USD) == {:ok, usd(0)}
+    assert Money.parse("1000.0e1", :USD) == {:ok, usd(1_000_000)}
+    assert Money.parse("1000.0E1", :USD) == {:ok, usd(1_000_000)}
+    assert Money.parse("1000.0e+1", :USD) == {:ok, usd(1_000_000)}
+    assert Money.parse("1000.0E+1", :USD) == {:ok, usd(1_000_000)}
+    assert Money.parse("1000.0e-1", :USD) == {:ok, usd(10000)}
+    assert Money.parse("1000.0E-1", :USD) == {:ok, usd(10000)}
+    assert Money.parse("0.5e-1", :USD) == {:ok, usd(5)}
+
     assert Money.parse("1000.0", :WRONG) == :error
   end