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"). # Ignore package tarball (built via "mix hex.build").
week_budget-*.tar 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() @spec handle_request(Raxx.Request.t(), %{}) :: Raxx.Response.t()
def handle_request(req, state) def handle_request(req, state)
# GET budget information
def handle_request(%{method: :GET, path: ["budgets", uuid]}, _state) when uuid != "" do def handle_request(%{method: :GET, path: ["budgets", uuid]}, _state) when uuid != "" do
with {:ok, _} <- Ecto.UUID.dump(uuid), with {:ok, _} <- Ecto.UUID.dump(uuid),
%WeekBudget.DB.Budget{} = wb <- WeekBudget.DB.Budget.get_by_secret(uuid) do %WeekBudget.DB.Budget{} = wb <- WeekBudget.DB.Budget.get_by_secret(uuid) do
@ -23,38 +24,71 @@ defmodule WeekBudget.API.Server do
end end
end end
# POST new event into budget
def handle_request(%{method: :POST, path: ["budgets", uuid, "events"], body: body}, _state) def handle_request(%{method: :POST, path: ["budgets", uuid, "events"], body: body}, _state)
when uuid != "" and body != "" do when uuid != "" and body != "" do
with {:uuid, {:ok, _}} <- {:uuid, Ecto.UUID.dump(uuid)}, {status, data} =
{:wb, %WeekBudget.DB.Budget{} = wb} <- {:wb, WeekBudget.DB.Budget.get_by_secret(uuid)}, with {:uuid, {:ok, _}} <- {:uuid, Ecto.UUID.dump(uuid)},
{:json, {:ok, %{"amount" => amnt}}} when is_number(amnt) <- {:json, Jason.decode(body)}, {:wb, %WeekBudget.DB.Budget{} = wb} <- {:wb, WeekBudget.DB.Budget.get_by_secret(uuid)},
{:currency, {:ok, curr}} <- {:currency, Money.validate_currency(wb.amount.currency)}, {:json, {:ok, %{"amount" => amnt}}} when is_number(amnt) <-
{:money, %Money{} = money} <- {:money, WeekBudget.Core.MoneyUtils.create(curr, -amnt)} do {:json, Jason.decode(body)},
{:ok, event} = WeekBudget.DB.Event.create(wb, money) {:money, %Money{} = money} <-
event_json = serialize_event(event) {:money, WeekBudget.Core.MoneyUtils.create(wb.amount.currency, -amnt)} do
json_resp(:created, event_json) {:ok, event} = WeekBudget.DB.Event.create(wb, money)
else event_json = serialize_event(event)
{:uuid, _} -> json_resp(:bad_request, %{error: "Malformed UUID."}) {:created, event_json}
{:wb, _} -> json_resp(:not_found, %{error: "Budget not found."}) else
{:json, _} -> json_resp(:bad_request, %{error: "Cannot parse JSON."}) {:uuid, _} -> {:bad_request, %{error: "Malformed UUID."}}
{:currency, _} -> json_resp(:bad_request, %{error: "Invalid currency."}) {:wb, _} -> {:not_found, %{error: "Budget not found."}}
{:money, _} -> json_resp(:internal_server_error, %{error: "Cannot create money."}) {:json, _} -> {:bad_request, %{error: "Cannot parse JSON."}}
end {:currency, _} -> {:bad_request, %{error: "Invalid currency."}}
{:money, _} -> {:internal_server_error, %{error: "Cannot create money."}}
end
json_resp(status, data)
end 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 def handle_request(%{method: :POST, path: ["budgets"], body: body}, _state) when body != "" do
with {:json, {:ok, %{"amount" => amnt, "currency" => curr_str}}} {status, data} =
when is_number(amnt) and is_binary(curr_str) <- {:json, Jason.decode(body)}, with {:json, {:ok, %{"amount" => amnt, "currency" => curr_str}}}
{:currency, {:ok, curr}} <- {:currency, Money.validate_currency(curr_str)}, when is_number(amnt) and is_binary(curr_str) <- {:json, Jason.decode(body)},
{:money, %Money{} = money} <- {:money, WeekBudget.Core.MoneyUtils.create(curr, amnt)} do {:currency, {:ok, curr}} <- {:currency, Money.validate_currency(curr_str)},
{:ok, budget} = WeekBudget.DB.Budget.create(money) {:money, %Money{} = money} <- {:money, WeekBudget.Core.MoneyUtils.create(curr, amnt)} do
budget_json = serialize_budget(%WeekBudget.DB.Budget{budget | events: []}) {:ok, budget} = WeekBudget.DB.Budget.create(money)
json_resp(:created, budget_json) budget_json = serialize_budget(%WeekBudget.DB.Budget{budget | events: []})
else {:created, budget_json}
{:json, _} -> json_resp(:bad_request, %{error: "Cannot parse JSON."}) else
{:currency, _} -> json_resp(:bad_request, %{error: "Invalid currency."}) {:json, _} -> {:bad_request, %{error: "Cannot parse JSON."}}
{:money, _} -> json_resp(:internal_server_error, %{error: "Cannot create money."}) {:currency, _} -> {:bad_request, %{error: "Invalid currency."}}
end {:money, _} -> {:internal_server_error, %{error: "Cannot create money."}}
end
json_resp(status, data)
end end
def handle_request(req, _) do 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 frontends. It is normalised to a Money instance at first opportunity so it is believed that the
impact and potential for errors is minimal. impact and potential for errors is minimal.
""" """
@spec create(atom | string, integer | float) :: @spec create(atom | String.t(), integer | float) :: Money.t() | {:error, {module, String.t()}}
{:ok, Money.t()} | {:error, {module, String.t()}}
def create(currency, amount) def create(currency, amount)
def create(currency, amount) when is_integer(amount) do def create(currency, amount) when is_integer(amount) do

View file

@ -40,4 +40,20 @@ defmodule WeekBudget.DB.Budget do
} }
|> WeekBudget.DB.Repo.insert() |> WeekBudget.DB.Repo.insert()
end 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 end