Current section
Files
Jump to
Current section
Files
lib/Transfer.ex
defmodule SoftBank.Transfer do
use Ecto.Schema
import Ecto.Query
import Ecto.Changeset
alias SoftBank.Amount
alias SoftBank.Account
alias SoftBank.Transfer
alias SoftBank.Entry
alias SoftBank.Repo
@moduledoc """
Transfer from one account to another.
"""
embedded_schema do
field(:message, :integer)
field(:amount, Money.Ecto.Composite.Type)
field(:description, :string)
embeds_one(:sender, Account)
embeds_one(:recipient, Account)
end
def changeset(account, struct, params \\ %{}) do
struct
|> cast(params, [:message, :description])
|> validate_required([:description])
|> put_embed(:sender, account)
|> put_destination_customer(account)
end
defp put_destination_customer(%{valid?: false} = changeset, _), do: changeset
defp put_destination_customer(changeset, sender) do
account_number = get_change(changeset, :account_number)
if account_number == sender.account_number do
add_error(changeset, :recipient, "cannot transfer to the same account")
else
case Repo.one(from(a in Account, where: a.account_number == ^account_number)) do
%Account{} = account ->
put_embed(changeset, :recipient, account)
nil ->
add_error(changeset, :recipient, "is invalid")
end
end
end
## params must be of %Account{} type
def send(account, params) do
changeset = changeset(account, %Transfer{}, params)
if changeset.valid? do
transfer = apply_changes(changeset)
source_account = account
destination_account = transfer.recipient
amount =
case source_account.currency == destination_account.currency do
true -> transfer.amount
_ -> SoftBank.Currency.Conversion.convert(transfer.amount, destination_account.currency)
end
transfer = %{transfer | amount: amount}
transfer_request =
create_request(source_account, destination_account, transfer.description, amount)
case account.balance - amount > 0 do
true ->
entry_changeset = %Entry{
description:
"Transfer : " <>
transfer_request.debit.amount <>
" from " <>
transfer_request.debit.account <> " to " <> transfer_request.debit.account,
date: Ecto.Date.utc(),
amounts: [
%Amount{
amount: transfer_request.sender.amount,
type: "credit",
account_id: transfer_request.reciever.account.id
},
%Amount{
amount: transfer_request.sender.amount,
type: "debit",
account_id: transfer_request.sender.account.id
}
]
}
Repo.insert(entry_changeset)
{:ok, transfer}
false ->
changeset = add_error(changeset, :message, "insufficient funds")
{:error, changeset}
end
else
{:error, changeset}
end
end
defp create_request(source, destination, description, amount) do
%{
sender: %{
account: source.account_number,
description: source.description,
amount: source.amount
},
reciever: %{
account: destination.account_number,
description: destination.description,
amount: destination.amount
}
}
end
end