Add reset to backend

This commit is contained in:
Mikko Ahlroth 2019-05-30 00:12:20 +03:00
parent e6cbccaf6f
commit a9786d95cc
4 changed files with 80 additions and 29 deletions

2
backend/.gitignore vendored
View file

@ -22,3 +22,5 @@ erl_crash.dump
# Ignore package tarball (built via "mix hex.build").
week_budget-*.tar
.elixir_ls

View file

@ -11,6 +11,7 @@ defmodule WeekBudget.API.Server do
@spec handle_request(Raxx.Request.t(), %{}) :: Raxx.Response.t()
def handle_request(req, state)
# GET budget information
def handle_request(%{method: :GET, path: ["budgets", uuid]}, _state) when uuid != "" do
with {:ok, _} <- Ecto.UUID.dump(uuid),
%WeekBudget.DB.Budget{} = wb <- WeekBudget.DB.Budget.get_by_secret(uuid) do
@ -23,38 +24,71 @@ defmodule WeekBudget.API.Server do
end
end
# POST new event into budget
def handle_request(%{method: :POST, path: ["budgets", uuid, "events"], body: body}, _state)
when uuid != "" and body != "" do
with {:uuid, {:ok, _}} <- {:uuid, Ecto.UUID.dump(uuid)},
{:wb, %WeekBudget.DB.Budget{} = wb} <- {:wb, WeekBudget.DB.Budget.get_by_secret(uuid)},
{:json, {:ok, %{"amount" => amnt}}} when is_number(amnt) <- {:json, Jason.decode(body)},
{:currency, {:ok, curr}} <- {:currency, Money.validate_currency(wb.amount.currency)},
{:money, %Money{} = money} <- {:money, WeekBudget.Core.MoneyUtils.create(curr, -amnt)} do
{:ok, event} = WeekBudget.DB.Event.create(wb, money)
event_json = serialize_event(event)
json_resp(:created, event_json)
else
{:uuid, _} -> json_resp(:bad_request, %{error: "Malformed UUID."})
{:wb, _} -> json_resp(:not_found, %{error: "Budget not found."})
{:json, _} -> json_resp(:bad_request, %{error: "Cannot parse JSON."})
{:currency, _} -> json_resp(:bad_request, %{error: "Invalid currency."})
{:money, _} -> json_resp(:internal_server_error, %{error: "Cannot create money."})
end
{status, data} =
with {:uuid, {:ok, _}} <- {:uuid, Ecto.UUID.dump(uuid)},
{:wb, %WeekBudget.DB.Budget{} = wb} <- {:wb, WeekBudget.DB.Budget.get_by_secret(uuid)},
{:json, {:ok, %{"amount" => amnt}}} when is_number(amnt) <-
{:json, Jason.decode(body)},
{:money, %Money{} = money} <-
{:money, WeekBudget.Core.MoneyUtils.create(wb.amount.currency, -amnt)} do
{:ok, event} = WeekBudget.DB.Event.create(wb, money)
event_json = serialize_event(event)
{:created, event_json}
else
{:uuid, _} -> {:bad_request, %{error: "Malformed UUID."}}
{:wb, _} -> {:not_found, %{error: "Budget not found."}}
{:json, _} -> {:bad_request, %{error: "Cannot parse JSON."}}
{:currency, _} -> {:bad_request, %{error: "Invalid currency."}}
{:money, _} -> {:internal_server_error, %{error: "Cannot create money."}}
end
json_resp(status, data)
end
# PATCH budget with a new amount, deleting all events
def handle_request(%{method: :PATCH, path: ["budgets", uuid], body: body}, _state)
when uuid != "" and body != "" do
{status, data} =
with {:uuid, {:ok, _}} <- {:uuid, Ecto.UUID.dump(uuid)},
{:wb, %WeekBudget.DB.Budget{} = wb} <- {:wb, WeekBudget.DB.Budget.get_by_secret(uuid)},
{:json, {:ok, %{"amount" => amnt}}} when is_number(amnt) <-
{:json, Jason.decode(body)},
{:money, %Money{} = money} <-
{:money, WeekBudget.Core.MoneyUtils.create(wb.amount.currency, amnt)} do
{:ok, %{amount_update: budget}} = WeekBudget.DB.Budget.reset(wb, money)
budget_json = serialize_budget(%WeekBudget.DB.Budget{budget | events: []})
{:ok, budget_json}
else
{:uuid, _} -> {:bad_request, %{error: "Malformed UUID."}}
{:wb, _} -> {:not_found, %{error: "Budget not found."}}
{:json, _} -> {:bad_request, %{error: "Cannot parse JSON."}}
{:currency, _} -> {:bad_request, %{error: "Invalid currency."}}
{:money, _} -> {:internal_server_error, %{error: "Cannot create money."}}
end
json_resp(status, data)
end
# POST to create a new budget
def handle_request(%{method: :POST, path: ["budgets"], body: body}, _state) when body != "" do
with {:json, {:ok, %{"amount" => amnt, "currency" => curr_str}}}
when is_number(amnt) and is_binary(curr_str) <- {:json, Jason.decode(body)},
{:currency, {:ok, curr}} <- {:currency, Money.validate_currency(curr_str)},
{:money, %Money{} = money} <- {:money, WeekBudget.Core.MoneyUtils.create(curr, amnt)} do
{:ok, budget} = WeekBudget.DB.Budget.create(money)
budget_json = serialize_budget(%WeekBudget.DB.Budget{budget | events: []})
json_resp(:created, budget_json)
else
{:json, _} -> json_resp(:bad_request, %{error: "Cannot parse JSON."})
{:currency, _} -> json_resp(:bad_request, %{error: "Invalid currency."})
{:money, _} -> json_resp(:internal_server_error, %{error: "Cannot create money."})
end
{status, data} =
with {:json, {:ok, %{"amount" => amnt, "currency" => curr_str}}}
when is_number(amnt) and is_binary(curr_str) <- {:json, Jason.decode(body)},
{:currency, {:ok, curr}} <- {:currency, Money.validate_currency(curr_str)},
{:money, %Money{} = money} <- {:money, WeekBudget.Core.MoneyUtils.create(curr, amnt)} do
{:ok, budget} = WeekBudget.DB.Budget.create(money)
budget_json = serialize_budget(%WeekBudget.DB.Budget{budget | events: []})
{:created, budget_json}
else
{:json, _} -> {:bad_request, %{error: "Cannot parse JSON."}}
{:currency, _} -> {:bad_request, %{error: "Invalid currency."}}
{:money, _} -> {:internal_server_error, %{error: "Cannot create money."}}
end
json_resp(status, data)
end
def handle_request(req, _) do

View file

@ -8,8 +8,7 @@ defmodule WeekBudget.Core.MoneyUtils do
frontends. It is normalised to a Money instance at first opportunity so it is believed that the
impact and potential for errors is minimal.
"""
@spec create(atom | string, integer | float) ::
{:ok, Money.t()} | {:error, {module, String.t()}}
@spec create(atom | String.t(), integer | float) :: Money.t() | {:error, {module, String.t()}}
def create(currency, amount)
def create(currency, amount) when is_integer(amount) do

View file

@ -40,4 +40,20 @@ defmodule WeekBudget.DB.Budget do
}
|> WeekBudget.DB.Repo.insert()
end
@doc """
Reset budget to given amount an delete all events.
"""
@spec reset(__MODULE__.t(), Money.t()) ::
{:ok, %{amount_update: __MODULE__.t(), delete_events: any()}} | {:error, any()}
def reset(budget, amount) do
update_cset =
budget
|> Ecto.Changeset.cast(%{amount: amount}, [:amount])
Ecto.Multi.new()
|> Ecto.Multi.update(:amount_update, update_cset)
|> Ecto.Multi.delete_all(:delete_events, Ecto.assoc(budget, :events))
|> WeekBudget.DB.Repo.transaction()
end
end