Skip to content

Commit

Permalink
chore(balance): schedule a balance update when necessary
Browse files Browse the repository at this point in the history
  • Loading branch information
Gladear committed Jan 17, 2025
1 parent 9a0605c commit a4df12e
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 23 deletions.
19 changes: 14 additions & 5 deletions apps/app/lib/app/balance/balance_configs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ defmodule App.Balance.BalanceConfigs do
import Ecto.Query

alias App.Accounts.User
alias App.Balance
alias App.Balance.BalanceConfig
alias App.Books.BookMember
alias App.Repo
Expand Down Expand Up @@ -85,13 +86,21 @@ defmodule App.Balance.BalanceConfigs do
@doc """
Link a balance configuration to a list of peers.
"""
@spec link_balance_config_to_peers(BalanceConfig.t(), [Peer.t()]) :: :ok
def link_balance_config_to_peers(%BalanceConfig{} = balance_config, peers) do
@spec link_balance_config_to_peers(BalanceConfig.t(), [Peer.t()], Book.t()) :: :ok
def link_balance_config_to_peers(%BalanceConfig{} = balance_config, peers, book) do
peer_ids = Enum.map(peers, & &1.id)

{_, nil} =
from([peer: peer] in Peer.base_query(), where: peer.id in ^peer_ids)
|> Repo.update_all(set: [balance_config_id: balance_config.id])
{:ok, _changes} =
Ecto.Multi.new()
|> Ecto.Multi.update_all(
:peers,
from([peer: peer] in Peer.base_query(), where: peer.id in ^peer_ids),
set: [balance_config_id: balance_config.id]
)
|> Ecto.Multi.run(:balance_job, fn _repo, _changes ->
Balance.schedule_balance_update(book.id)
end)
|> Repo.transaction()

:ok
end
Expand Down
59 changes: 48 additions & 11 deletions apps/app/lib/app/transfers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ defmodule App.Transfers do

import Ecto.Query

alias App.Balance
alias App.Books.Book
alias App.Books.BookMember
alias App.Repo
Expand Down Expand Up @@ -173,6 +174,9 @@ defmodule App.Transfers do
end,
[]
)
|> Ecto.Multi.run(:balance_job, fn _repo, _changes ->
Balance.schedule_balance_update(book.id)
end)
|> Repo.transaction()

case result do
Expand All @@ -187,9 +191,18 @@ defmodule App.Transfers do
@spec update_money_transfer(MoneyTransfer.t(), map()) ::
{:ok, MoneyTransfer.t()} | {:error, Ecto.Changeset.t()}
def update_money_transfer(%MoneyTransfer{} = money_transfer, attrs) do
money_transfer
|> MoneyTransfer.changeset(attrs)
|> Repo.update()
result =
Ecto.Multi.new()
|> Ecto.Multi.update(:money_transfer, MoneyTransfer.changeset(money_transfer, attrs))
|> Ecto.Multi.run(:balance_job, fn _repo, _changes ->
Balance.schedule_balance_update(money_transfer.book_id)
end)
|> Repo.transaction()

case result do
{:ok, %{money_transfer: money_transfer}} -> {:ok, money_transfer}
{:error, :money_transfer, changeset, _changes} -> {:error, changeset}
end
end

@doc """
Expand All @@ -198,7 +211,18 @@ defmodule App.Transfers do
@spec delete_money_transfer(MoneyTransfer.t()) ::
{:ok, MoneyTransfer.t()} | {:error, Ecto.Changeset.t()}
def delete_money_transfer(%MoneyTransfer{} = money_transfer) do
Repo.delete(money_transfer)
result =
Ecto.Multi.new()
|> Ecto.Multi.delete(:money_transfer, money_transfer)
|> Ecto.Multi.run(:balance_job, fn _repo, _changes ->
Balance.schedule_balance_update(money_transfer.book_id)
end)
|> Repo.transaction()

case result do
{:ok, %{money_transfer: money_transfer}} -> {:ok, money_transfer}
{:error, :money_transfer, changeset, _changes} -> {:error, changeset}
end
end

@doc """
Expand All @@ -216,13 +240,26 @@ defmodule App.Transfers do
@spec create_reimbursement(Book.t(), map()) ::
{:ok, MoneyTransfer.t()} | {:error, Ecto.Changeset.t()}
def create_reimbursement(%Book{} = book, attrs) do
%MoneyTransfer{
book_id: book.id,
type: :reimbursement,
balance_means: :divide_equally
}
|> MoneyTransfer.reimbursement_changeset(attrs)
|> Repo.insert()
changeset =
%MoneyTransfer{
book_id: book.id,
type: :reimbursement,
balance_means: :divide_equally
}
|> MoneyTransfer.reimbursement_changeset(attrs)

result =
Ecto.Multi.new()
|> Ecto.Multi.insert(:reimbursement, changeset)
|> Ecto.Multi.run(:abalnce_job, fn _repo, _changes ->
Balance.schedule_balance_update(book.id)
end)
|> Repo.transaction()

case result do
{:ok, %{reimbursement: reimbursement}} -> {:ok, reimbursement}
{:error, :reimbursement, changeset, _changes} -> {:error, changeset}
end
end

@doc """
Expand Down
27 changes: 27 additions & 0 deletions apps/app/test/app/balance/balance_configs_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule App.Balance.BalanceConfigsTest do
import App.TransfersFixtures

alias App.Balance.BalanceConfigs
alias App.Balance.CacheUpdaterWorker

describe "get_balance_config_of_member/1" do
test "returns the balance config of the member" do
Expand Down Expand Up @@ -112,6 +113,32 @@ defmodule App.Balance.BalanceConfigsTest do
end
end

describe "link_balance_config_to_peers/3" do
test "links a balance config to the given peers" do
balance_config = balance_config_fixture()
book = book_fixture()
member = book_member_fixture(book)
transfer = money_transfer_fixture(book, tenant_id: member.id)
peer = peer_fixture(transfer, member_id: member.id)

:ok = BalanceConfigs.link_balance_config_to_peers(balance_config, [peer], book)

assert Repo.reload!(peer).balance_config_id == balance_config.id
end

test "schedules a job to update the book members balance" do
balance_config = balance_config_fixture()
book = book_fixture()
member = book_member_fixture(book)
transfer = money_transfer_fixture(book, tenant_id: member.id)
peer = peer_fixture(transfer, member_id: member.id)

:ok = BalanceConfigs.link_balance_config_to_peers(balance_config, [peer], book)

assert_enqueued(worker: CacheUpdaterWorker, args: %{book_id: book.id})
end
end

describe "change_balance_config_revenues/2" do
setup do
%{balance_config: balance_config_fixture()}
Expand Down
52 changes: 50 additions & 2 deletions apps/app/test/app/transfers_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ defmodule App.TransfersTest do
import App.BooksFixtures
import App.TransfersFixtures

alias App.Repo

alias App.Balance.CacheUpdaterWorker
alias App.Books.Book
alias App.Books.BookMember
alias App.Repo
alias App.Transfers
alias App.Transfers.MoneyTransfer
alias App.Transfers.Peer
Expand Down Expand Up @@ -247,6 +247,18 @@ defmodule App.TransfersTest do
assert Enum.empty?(transfer.peers)
end

test "schedules a job to update the book balance", %{book: book, member: member} do
{:ok, _transfer} =
Transfers.create_money_transfer(
book,
member,
:payment,
money_transfer_attributes(tenant_id: member.id)
)

assert_enqueued(worker: CacheUpdaterWorker, args: %{book_id: book.id})
end

test "sets balance means", %{book: book, member: member} do
assert {:ok, transfer} =
Transfers.create_money_transfer(
Expand Down Expand Up @@ -393,6 +405,16 @@ defmodule App.TransfersTest do
assert peer.member_id == other_member.id
end

test "schedules a job to update the book balance", %{
book: book,
money_transfer: money_transfer
} do
assert {:ok, _updated} =
Transfers.update_money_transfer(money_transfer, %{})

assert_enqueued(worker: CacheUpdaterWorker, args: %{book_id: book.id})
end

test "does not update book", %{book: book, money_transfer: money_transfer} do
other_book = book_fixture()

Expand Down Expand Up @@ -458,6 +480,15 @@ defmodule App.TransfersTest do
assert deleted_transfer.id == money_transfer.id
end

test "schedules a job to update the book balance", %{
book: book,
money_transfer: money_transfer
} do
assert {:ok, _deleted_transfer} = Transfers.delete_money_transfer(money_transfer)

assert_enqueued(worker: CacheUpdaterWorker, args: %{book_id: book.id})
end

test "deleted related peers", %{book: book, member: member} do
money_transfer = money_transfer_fixture(book, tenant_id: member.id)
_peer = peer_fixture(money_transfer, member_id: member.id)
Expand Down Expand Up @@ -495,6 +526,23 @@ defmodule App.TransfersTest do
assert money_transfer.balance_means == :divide_equally
end

test "schedules a job to update the book balance", %{
book: book,
member1: member1,
member2: member2
} do
{:ok, _transfer} =
Transfers.create_reimbursement(
book,
money_transfer_attributes(
tenant_id: member1.id,
peers: [%{member_id: member2.id}]
)
)

assert_enqueued(worker: CacheUpdaterWorker, args: %{book_id: book.id})
end

test "cannot create a payment or an income", %{book: book, member1: member1, member2: member2} do
assert {:ok, money_transfer} =
Transfers.create_reimbursement(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,13 @@ defmodule AppWeb.BookMemberRevenuesTransfersLive do

@impl Phoenix.LiveView
def handle_event("submit", params, socket) do
book_member = socket.assigns.book_member
%{book: book, book_member: book_member} = socket.assigns

peer_ids = Map.get(params, "peer_ids", [])
peers = list_peers_of_member(peer_ids, book_member)

balance_config = BalanceConfigs.get_balance_config_of_member(book_member)
:ok = BalanceConfigs.link_balance_config_to_peers(balance_config, peers)
:ok = BalanceConfigs.link_balance_config_to_peers(balance_config, peers, book)

redirect_path = redirect_path(book_member, socket.assigns.live_action)
{:noreply, push_navigate(socket, to: redirect_path)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,12 +321,13 @@ defmodule AppWeb.BookTransferFormLive do
select:
struct(money_transfer, [
:id,
:type,
:label,
:amount,
:type,
:date,
:balance_means,
:book_id,
:tenant_id,
:amount,
:balance_means,
peers: [
:id,
:member_id,
Expand Down

0 comments on commit a4df12e

Please sign in to comment.