Skip to content

Commit

Permalink
finished withdraw, create transiction
Browse files Browse the repository at this point in the history
  • Loading branch information
fabiobarboza7 committed Feb 28, 2021
1 parent 9641d01 commit 8aec28c
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 43 deletions.
4 changes: 3 additions & 1 deletion lib/rocketpay.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
defmodule Rocketpay do
alias Rocketpay.Users.Create, as: UserCreate

alias Rocketpay.Accouns.Deposit
alias Rocketpay.Accounts.{Deposit, Withdraw}

defdelegate create_user(params), to: UserCreate, as: :call

defdelegate deposit(params), to: Deposit, as: :call
defdelegate withdraw(params), to: Withdraw, as: :call

end
4 changes: 2 additions & 2 deletions lib/rocketpay/account.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ defmodule Rocketpay.Account do
timestamps()
end

def changeset(params) do
%__MODULE__{}
def changeset(struct \\ %__MODULE__{}, params) do
struct
|> cast(params, @required_params)
|> validate_required(@required_params)
|> check_constraint(:balance, name: :balance_must_be_positive_or_zero)
Expand Down
48 changes: 10 additions & 38 deletions lib/rocketpay/accounts/deposit.ex
Original file line number Diff line number Diff line change
@@ -1,45 +1,17 @@
defmodule Rocketpay.Accounts.Deposit do
alias Ecto.Multi
alias Rocketpay.Accounts.Operation
alias Rocketpay.Repo

alias Rocketpay.{Account, Repo}

def call(%{"id" => id, "value" => value}) do
Multi.new()
|> Multi.run(:account, fn repo, _changes -> get_account(repo, id) end)
|> Multi.run(:update_balance, fn repo, %{account: account} ->
update_balance(repo, account, value)
end)
def call(params) do
params
|> Operation.call(:deposit)
|> run_transaction()
end

defp get_account(repo, id) do
case repo.get(Account, id) do
nil -> {:error, "Account, not found!"}
account -> {:ok, account}
defp run_transaction(multi) do
case Repo.transaction(multi) do
{:error, _opration, reason, _changes} -> {:error, reason}
{:ok, %{update_balance: account}} -> {:ok, account}
end
end

defp update_balance(repo, account, value) do
account
|> sum_values(value)
|> update_account(repo)
end

defp sum_values(%Account{balance: balance}, value) do
value
|>Decimal.cast()
|> handle_cast(balance)
end

defp handle_cast({:ok, value}, balance), do: Decimal.add(value, balance)
defp handle_cast(:error, _balanace), do: {:error, "Invalid deposit value!"}

defp update_account({:error, _reason} = error, _repo), do: error

defp update_account(value, repo) do
params = %{balance: value}

params
|> Account.changeset()
|> repo.update()
end
end
54 changes: 54 additions & 0 deletions lib/rocketpay/accounts/operation.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
defmodule Rocketpay.Accounts.Operation do
alias Ecto.Multi

alias Rocketpay.{Account, Repo}

def call(%{"id" => id, "value" => value}, operation) do
operation_name = account_operation_name(operation)

Multi.new()
|> Multi.run(operation_name, fn repo, _changes -> get_account(repo, id) end)
|> Multi.run(:update_balance, fn repo, changes ->
account = Map.get(changes, operation_name)
update_balance(repo, account, value, operation)
end)
end

defp get_account(repo, id) do
case repo.get(Account, id) do
nil -> {:error, "Account not found!"}
account -> {:ok, account}
end
end

defp update_balance(repo, account, value, operation) do
account
|> operation(value, operation)
|> update_account(repo, account)
end

defp operation(%Account{balance: balance}, value, operation) do
value
|>Decimal.cast()
|> handle_cast(balance, operation)
end

defp handle_cast({:ok, value}, balance, :deposit), do: Decimal.add(balance, value)
defp handle_cast({:ok, value}, balance, :withdraw), do: Decimal.sub(balance, value)
defp handle_cast(:error, _balanace, operation), do: {:error, "Invalid #{operation} value!"}

defp update_account({:error, _reason} = error, _repo, _account), do: error

defp update_account(value, repo, account) do
params = %{balance: value}

account
|> Account.changeset(params)
|> repo.update()
end

defp account_operation_name(operation) do
"account_#{Atom.to_string(operation)}"
|> String.to_atom()
end
end
26 changes: 26 additions & 0 deletions lib/rocketpay/accounts/transaction.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Rocketpay.Accounts.Transaction do
alias Ecto.Multi
alias Rocketpay.Repo
alias Rocketpay.Accounts.Operation

def call(%{"from" => from_id, "to" => to_id, "value" => value}) do
withdraw_params = build_params(from_id, value)
deposit_params = build_params(to_id, value)

Multi.new()
|> Multi.merge(fn _changes -> Operation.call(withdraw_params, :withdraw) end)
|> Multi.merge(fn _changes -> Operation.call(deposit_params, :deposit) end)
|> run_transaction()
end

defp build_params(id, value), do: %{"id" => id, "value" => value}

defp run_transaction(multi) do
case Repo.transaction(multi) do
{:error, _opration, reason, _changes} ->
{:error, reason}
{:ok, %{deposit: to_account, withdraw: from_account}} ->
{:ok, %{to_account: to_account, from_account: from_account}}
end
end
end
17 changes: 17 additions & 0 deletions lib/rocketpay/accounts/withdraw.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule Rocketpay.Accounts.Withdraw do
alias Rocketpay.Accounts.Operation
alias Rocketpay.Repo

def call(params) do
params
|> Operation.call(:withdraw)
|> run_transaction()
end

defp run_transaction(multi) do
case Repo.transaction(multi) do
{:error, _opration, reason, _changes} -> {:error, reason}
{:ok, %{update_balance: account}} -> {:ok, account}
end
end
end
6 changes: 5 additions & 1 deletion lib/rocketpay_web/controllers/accounts_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ defmodule RocketpayWeb.AccountsController do
end

def withdraw(conn, params) do

with {:ok, %Account{} = account} <- Rocketpay.withdraw(params) do
conn
|> put_status(:ok)
|> render("update.json", account: account)
end
end
end
18 changes: 18 additions & 0 deletions lib/rocketpay_web/views/accounts_view.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule RocketpayWeb.AccountsView do
alias Rocketpay.Account

def render("update.json", %{
account: %Account{
id: account_id,
balance: balance
}
}) do
%{
message: "Ballance changed successfully",
account: %{
id: account_id,
balance: balance
}
}
end
end
4 changes: 4 additions & 0 deletions lib/rocketpay_web/views/error_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ defmodule RocketpayWeb.ErrorView do
%{message: translate_errors(changeset)}
end

def render("400.json", %{result: message}) do
%{message: message}
end

defp translate_errors(changeset) do
traverse_errors(changeset, fn {msg, opts} ->
Enum.reduce(opts, msg, fn {key, value}, acc ->
Expand Down
3 changes: 2 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ defmodule Rocketpay.MixProject do
{:jason, "~> 1.0"},
{:plug_cowboy, "~> 2.0"},
{:credo, "~> 1.5", only: [:dev, :test], runtime: false},
{:bcrypt_elixir, "~> 2.0"}
{:bcrypt_elixir, "~> 2.0"},
{:decimal, "~> 2.0"}
]
end

Expand Down

0 comments on commit 8aec28c

Please sign in to comment.