Skip to content

Commit

Permalink
chore(balance): make balance error an embedded schema
Browse files Browse the repository at this point in the history
  • Loading branch information
Gladear committed Jan 17, 2025
1 parent 631e224 commit d033cf3
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 39 deletions.
16 changes: 5 additions & 11 deletions apps/app/lib/app/balance.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ defmodule App.Balance do

alias App.Repo

alias App.Balance.BalanceError
alias App.Books.BookMember
alias App.Transfers
alias App.Transfers.Peer

@type error_reasons :: [%{uniq_hash: String.t(), kind: atom(), extra: map(), private: map()}]

@doc """
Compute the `:balance` field of book members.
"""
Expand Down Expand Up @@ -116,14 +115,9 @@ defmodule App.Balance do
defp maybe_set_weight_by_income_total_weight(transfer, peers_without_revenues) do
error_reasons =
Enum.map(peers_without_revenues, fn peer ->
%{
uniq_hash: "revenues_missing_#{peer.member_id}",
kind: :revenues_missing,
extra: %{
member_id: peer.member_id
},
private: %{}
}
BalanceError.new(:revenues_missing, %{
member_id: peer.member_id
})
end)

{:error, error_reasons, transfer}
Expand Down Expand Up @@ -282,7 +276,7 @@ defmodule App.Balance do
The total sum of balanced money must be equal to 0, otherwise the function will crash.
"""
@spec transactions([BookMember.t()]) :: {:ok, [transaction()]} | {:error, error_reasons()}
@spec transactions([BookMember.t()]) :: {:ok, [transaction()]} | {:error, [BalanceError.t()]}
def transactions(members) do
error_reasons =
Enum.find_value(members, fn member ->
Expand Down
36 changes: 36 additions & 0 deletions apps/app/lib/app/balance/balance_error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
defmodule App.Balance.BalanceError do
@moduledoc """
Balance errors are instantiated when the balance of a book cannot be computed,
and are used to store the kind of error along with some extra information.
"""
use Ecto.Schema

@type t :: %__MODULE__{
kind: atom(),
extra: map(),
uniq_hash: String.t(),
private: map()
}

@primary_key false
embedded_schema do
field :kind, Ecto.Enum, values: [:missing_revenues]
field :extra, :map

field :uniq_hash, :string, virtual: true
field :private, :map, virtual: true, default: %{}
end

@spec new(kind :: atom(), extra :: map()) :: t()
def new(kind, extra) when is_atom(kind) and is_map(extra) do
%__MODULE__{
kind: kind,
extra: extra,
uniq_hash: uniq_hash(kind, extra)
}
end

defp uniq_hash(:revenues_missing, extra) do
"revenues_missing_#{extra.member_id}"
end
end
5 changes: 3 additions & 2 deletions apps/app/test/app/balance_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ defmodule App.BalanceTest do
import App.TransfersFixtures

alias App.Balance
alias App.Balance.BalanceError

describe "fill_members_balance/1" do
setup do
Expand Down Expand Up @@ -299,7 +300,7 @@ defmodule App.BalanceTest do
expected_hash = "revenues_missing_#{member1_id}"

assert member1.balance_errors == [
%{
%BalanceError{
kind: :revenues_missing,
uniq_hash: expected_hash,
extra: %{member_id: member1_id},
Expand All @@ -308,7 +309,7 @@ defmodule App.BalanceTest do
]

assert member2.balance_errors == [
%{
%BalanceError{
kind: :revenues_missing,
uniq_hash: expected_hash,
extra: %{member_id: member1_id},
Expand Down
54 changes: 28 additions & 26 deletions apps/app_web/lib/app_web/live/books/book_balance_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule AppWeb.BookBalanceLive do
import AppWeb.BooksComponents, only: [balance_card: 1]

alias App.Balance
alias App.Balance.BalanceError
alias App.Books.Book
alias App.Books.BookMember
alias App.Books.Members
Expand Down Expand Up @@ -33,15 +34,15 @@ defmodule AppWeb.BookBalanceLive do
</.link>
</.card_grid>
<%= if @transaction_errors != nil do %>
<%= if @balance_errors != nil do %>
<section class="space-y-4" id="transaction-errors">
<.alert kind={:error}>
{gettext("Some information is missing to balance the book")}
</.alert>
<.transaction_error_tile
:for={transaction_error <- @transaction_errors}
<.balance_error_tile
:for={balance_error <- @balance_errors}
book={@book}
{transaction_error}
balance_error={balance_error}
/>
</section>
<% else %>
Expand Down Expand Up @@ -75,24 +76,25 @@ defmodule AppWeb.BookBalanceLive do
end

attr :book, Book, required: true
attr :kind, :atom, required: true
attr :extra, :map, required: true
attr :private, :map, required: true

defp transaction_error_tile(%{kind: :revenues_missing} = assigns) do
~H"""
<.link navigate={~p"/books/#{@book}/members/#{@extra.member_id}"} class="block">
<.tile class="justify-between">
<div class="truncate">
<span class="label">{@private.member_nickname}</span>
<span class="font-normal">did not set their revenues.</span>
</div>
<.button kind={:ghost}>
{gettext("Fix it")} <.icon name={:chevron_right} />
</.button>
</.tile>
</.link>
"""
attr :balance_error, BalanceError, required: true

defp balance_error_tile(assigns) do
case assigns.balance_error.kind do
:revenues_missing ->
~H"""
<.link navigate={~p"/books/#{@book}/members/#{@balance_error.extra.member_id}"} class="block">
<.tile class="justify-between">
<div class="truncate">
<span class="label">{@balance_error.private.member_nickname}</span>
<span class="font-normal">did not set their revenues.</span>
</div>
<.button kind={:ghost}>
{gettext("Fix it")} <.icon name={:chevron_right} />
</.button>
</.tile>
</.link>
"""
end
end

# Highlight the nickname of the current member
Expand Down Expand Up @@ -131,18 +133,18 @@ defmodule AppWeb.BookBalanceLive do
)
|> assign_transactions(members)

{:ok, socket, temporary_assigns: [transaction_errors: []]}
{:ok, socket, temporary_assigns: [balance_errors: []]}
end

defp assign_transactions(socket, members) do
case Balance.transactions(members) do
{:ok, transactions} ->
socket
|> assign(transaction_errors: nil)
|> assign(balance_errors: nil)
|> stream(:transactions, transactions)

{:error, reasons} ->
assign(socket, transaction_errors: reasons)
{:error, balance_errors} ->
assign(socket, balance_errors: balance_errors)
end
end
end

0 comments on commit d033cf3

Please sign in to comment.