Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for both ExMoney and Money #2

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .dialyzer_ignore.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
{"lib/ex_double_entry/money_proxy.ex"}
]
52 changes: 37 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,46 @@ jobs:
strategy:
matrix:
include:
- elixir: 1.12.3
otp: 24.0
env: test
- elixir: 1.12.3
otp: 24.0
env: test_mysql
- elixir: 1.12.3

- elixir: 1.13.3
otp: 24.2
env: test_money
- elixir: 1.13.3
otp: 24.2
env: test_mysql_money
- elixir: 1.13.3
otp: 24.2
env: test_ex_money
- elixir: 1.13.3
otp: 24.2
env: test_mysql_ex_money

- elixir: 1.13.3
otp: 23.3
env: test
- elixir: 1.12.3
env: test_money
- elixir: 1.13.3
otp: 23.3
env: test_mysql
- elixir: 1.12.3
env: test_mysql_money
- elixir: 1.13.3
otp: 23.3
env: test_ex_money
- elixir: 1.13.3
otp: 23.3
env: test_mysql_ex_money

- elixir: 1.13.3
otp: 22.3
env: test_money
- elixir: 1.13.3
otp: 22.3
env: test_mysql_money
- elixir: 1.13.3
otp: 22.3
env: test
- elixir: 1.12.3
env: test_ex_money
- elixir: 1.13.3
otp: 22.3
env: test_mysql
env: test_mysql_ex_money

services:
postgres:
image: postgres
Expand Down Expand Up @@ -51,7 +73,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up Elixir
uses: erlef/setup-elixir@885971a72ed1f9240973bd92ab57af8c1aa68f24
uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ def deps do
# pick one DB package
{:postgrex, ">= 0.0.0"},
{:myxql, ">= 0.0.0"},
# pick one money package
{:money, "~> 1.9"},
{:ex_money, "~> 5.9"},
]
end
```
Expand Down
18 changes: 18 additions & 0 deletions config/test_ex_money.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Config

config :ex_double_entry,
db: :postgres,
money: :ex_money

config :ex_double_entry, ExDoubleEntry.Repo,
username: System.get_env("POSTGRES_DB_USERNAME", "postgres"),
password: System.get_env("POSTGRES_DB_PASSWORD", "postgres"),
database: System.get_env("POSTGRES_DB_NAME", "ex_double_entry_test"),
hostname: System.get_env("POSTGRES_DB_HOST", "localhost"),
pool: Ecto.Adapters.SQL.Sandbox,
show_sensitive_data_on_connection_error: true,
timeout: :infinity,
queue_target: 200,
queue_interval: 10

config :logger, level: :info
3 changes: 2 additions & 1 deletion config/test.exs → config/test_money.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Config

config :ex_double_entry,
db: :postgres
db: :postgres,
money: :money

config :ex_double_entry, ExDoubleEntry.Repo,
username: System.get_env("POSTGRES_DB_USERNAME", "postgres"),
Expand Down
18 changes: 18 additions & 0 deletions config/test_mysql_ex_money.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Config

config :ex_double_entry,
db: :mysql,
money: :ex_money

config :ex_double_entry, ExDoubleEntry.Repo,
username: System.get_env("MYSQL_DB_USERNAME", "root"),
password: System.get_env("MYSQL_DB_PASSWORD", ""),
database: System.get_env("MYSQL_DB_NAME", "ex_double_entry_test"),
hostname: System.get_env("MYSQL_DB_HOST", "localhost"),
pool: Ecto.Adapters.SQL.Sandbox,
show_sensitive_data_on_connection_error: true,
timeout: :infinity,
queue_target: 200,
queue_interval: 10

config :logger, level: :info
3 changes: 2 additions & 1 deletion config/test_mysql.exs → config/test_mysql_money.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Config

config :ex_double_entry,
db: :mysql
db: :mysql,
money: :money

config :ex_double_entry, ExDoubleEntry.Repo,
username: System.get_env("MYSQL_DB_USERNAME", "root"),
Expand Down
6 changes: 3 additions & 3 deletions lib/ex_double_entry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ defmodule ExDoubleEntry do
## Examples

iex> %ExDoubleEntry.Transfer{
iex> money: Money.new(42, :USD),
iex> from: %ExDoubleEntry.Account{identifier: :checking, currency: :USD, balance: Money.new(42, :USD), positive_only?: false},
iex> to: %ExDoubleEntry.Account{identifier: :savings, currency: :USD, balance: Money.new(0, :USD)},
iex> money: MoneyProxy.new(42, :USD),
iex> from: %ExDoubleEntry.Account{identifier: :checking, currency: :USD, balance: MoneyProxy.new(42, :USD), positive_only?: false},
iex> to: %ExDoubleEntry.Account{identifier: :savings, currency: :USD, balance: MoneyProxy.new(0, :USD)},
iex> code: :deposit
iex> }
iex> |> ExDoubleEntry.transfer!()
Expand Down
21 changes: 21 additions & 0 deletions lib/ex_double_entry/ecto_types/amount.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
if Code.ensure_loaded?(Ecto.Type) do
defmodule ExDoubleEntry.EctoType.Amount do
if macro_exported?(Ecto.Type, :__using__, 1) do
use Ecto.Type
else
@behaviour Ecto.Type
end

def type, do: :integer

def cast(val) when is_integer(val), do: {:ok, val}
def cast(%Decimal{} = val), do: {:ok, Decimal.to_integer(val)}
def cast(_), do: :error

def load(val) when is_integer(val), do: {:ok, val}

def dump(val) when is_integer(val), do: {:ok, val}
def dump(%Decimal{} = val), do: {:ok, Decimal.to_integer(val)}
def dump(_), do: :error
end
end
2 changes: 1 addition & 1 deletion lib/ex_double_entry/ecto_types/currency.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if Code.ensure_loaded?(Ecto.Type) do

def cast(val)

def cast(%Money{currency: currency}), do: {:ok, currency}
def cast(%{currency: currency}), do: {:ok, currency}

def cast(atom) when is_atom(atom), do: {:ok, atom}

Expand Down
49 changes: 49 additions & 0 deletions lib/ex_double_entry/money_proxy.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
defmodule ExDoubleEntry.MoneyProxy do
@moduledoc """
The `Money` and `ExMoney` packages both claim the `Money` module namespace,
therefore this proxy module normalises the function uses so that ExDoubleEntry
can be used by either.
"""

defdelegate new(amount, currency), to: Money

def add(a, b) do
if function_exported?(Money, :add!, 2) do
apply(Money, :add!, [a, b])
else
apply(Money, :add, [a, b])
end
end

def subtract(a, b) do
if function_exported?(Money, :sub!, 2) do
apply(Money, :sub!, [a, b])
else
apply(Money, :subtract, [a, b])
end
end

def cmp(a, b) do
if function_exported?(Money, :compare!, 2) do
apply(Money, :compare!, [a, b])
else
apply(Money, :cmp, [a, b])
end
end

def neg(money) do
if function_exported?(Money, :neg, 1) do
apply(Money, :neg, [money])
else
apply(Money, :mult!, [money, -1])
end
end

def positive?(money) do
if function_exported?(Money, :positive?, 1) do
apply(Money, :positive?, [money])
else
apply(Money, :cmp!, [money, Money.new(0, money.currency)]) >= 0
end
end
end
10 changes: 5 additions & 5 deletions lib/ex_double_entry/schemas/account_balance.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ defmodule ExDoubleEntry.AccountBalance do
use Ecto.Schema
import Ecto.{Changeset, Query}

alias ExDoubleEntry.{Account, AccountBalance}
alias ExDoubleEntry.{Account, AccountBalance, EctoType}

schema "#{ExDoubleEntry.db_table_prefix()}account_balances" do
field(:identifier, ExDoubleEntry.EctoType.Identifier)
field(:currency, ExDoubleEntry.EctoType.Currency)
field(:scope, ExDoubleEntry.EctoType.Scope)
field(:balance_amount, :integer)
field(:identifier, EctoType.Identifier)
field(:currency, EctoType.Currency)
field(:scope, EctoType.Scope)
field(:balance_amount, EctoType.Amount)

timestamps(type: :utc_datetime_usec)
end
Expand Down
20 changes: 10 additions & 10 deletions lib/ex_double_entry/schemas/line.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ defmodule ExDoubleEntry.Line do
use Ecto.Schema
import Ecto.Changeset

alias ExDoubleEntry.{AccountBalance, Line}
alias ExDoubleEntry.{AccountBalance, EctoType, Line, MoneyProxy}

schema "#{ExDoubleEntry.db_table_prefix()}lines" do
field(:account_identifier, ExDoubleEntry.EctoType.Identifier)
field(:account_scope, ExDoubleEntry.EctoType.Scope)
field(:currency, ExDoubleEntry.EctoType.Currency)
field(:amount, :integer)
field(:balance_amount, :integer)
field(:code, ExDoubleEntry.EctoType.Identifier)
field(:partner_identifier, ExDoubleEntry.EctoType.Identifier)
field(:partner_scope, ExDoubleEntry.EctoType.Scope)
field(:account_identifier, EctoType.Identifier)
field(:account_scope, EctoType.Scope)
field(:currency, EctoType.Currency)
field(:amount, EctoType.Amount)
field(:balance_amount, EctoType.Amount)
field(:code, EctoType.Identifier)
field(:partner_identifier, EctoType.Identifier)
field(:partner_scope, EctoType.Scope)
field(:metadata, :map)

belongs_to(:partner_line, Line)
Expand Down Expand Up @@ -55,7 +55,7 @@ defmodule ExDoubleEntry.Line do
currency: money.currency,
code: code,
amount: money.amount,
balance_amount: Money.add(account.balance, money).amount,
balance_amount: MoneyProxy.add(account.balance, money).amount,
partner_identifier: partner.identifier,
partner_scope: partner.scope,
metadata: metadata,
Expand Down
6 changes: 4 additions & 2 deletions lib/ex_double_entry/services/account.ex
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
defmodule ExDoubleEntry.Account do
@type t() :: %__MODULE__{}

@enforce_keys [:identifier, :currency]
defstruct [:id, :identifier, :scope, :currency, :balance, :positive_only?]

alias ExDoubleEntry.{Account, AccountBalance}
alias ExDoubleEntry.{Account, AccountBalance, MoneyProxy}

def present(nil), do: nil

Expand All @@ -13,7 +15,7 @@ defmodule ExDoubleEntry.Account do
currency: params.currency,
scope: params.scope,
positive_only?: positive_only?(params.identifier),
balance: Money.new(params.balance_amount, params.currency)
balance: MoneyProxy.new(params.balance_amount, params.currency)
}
end

Expand Down
Loading