mirror of
https://github.com/ash-project/ash_double_entry.git
synced 2024-09-19 13:03:19 +12:00
improvement: support updating transfer's amount (#8)
* support updating transfer's amount Signed-off-by: Tw <tw19881113@gmail.com> --------- Signed-off-by: Tw <tw19881113@gmail.com> Co-authored-by: Zach Daniel <zachary.s.daniel@gmail.com>
This commit is contained in:
parent
86a9b33eb1
commit
c113fa080d
2 changed files with 62 additions and 23 deletions
|
@ -9,32 +9,33 @@ defmodule AshDoubleEntry.Transfer.Changes.VerifyTransfer do
|
|||
require Ash.Query
|
||||
|
||||
def change(changeset, _opts, context) do
|
||||
if changeset.action.type == :update do
|
||||
if Enum.any?(
|
||||
[:from_account_id, :to_account_id, :amount, :id],
|
||||
if changeset.action.type == :update and
|
||||
Enum.any?(
|
||||
[:from_account_id, :to_account_id, :id],
|
||||
&Ash.Changeset.changing_attribute?(changeset, &1)
|
||||
) do
|
||||
Ash.Changeset.add_error(
|
||||
changeset,
|
||||
"Cannot modify a transfer's from_account_id, to_account_id, amount, or id"
|
||||
)
|
||||
else
|
||||
changeset
|
||||
end
|
||||
Ash.Changeset.add_error(
|
||||
changeset,
|
||||
"Cannot modify a transfer's from_account_id, to_account_id, or id"
|
||||
)
|
||||
else
|
||||
changeset
|
||||
|> Ash.Changeset.before_action(fn changeset ->
|
||||
timestamp = Ash.Changeset.get_attribute(changeset, :timestamp)
|
||||
if changeset.action.type == :create do
|
||||
timestamp = Ash.Changeset.get_attribute(changeset, :timestamp)
|
||||
|
||||
timestamp =
|
||||
case timestamp do
|
||||
nil -> System.system_time(:millisecond)
|
||||
timestamp -> DateTime.to_unix(timestamp, :millisecond)
|
||||
end
|
||||
timestamp =
|
||||
case timestamp do
|
||||
nil -> System.system_time(:millisecond)
|
||||
timestamp -> DateTime.to_unix(timestamp, :millisecond)
|
||||
end
|
||||
|
||||
ulid = AshDoubleEntry.ULID.generate(timestamp)
|
||||
ulid = AshDoubleEntry.ULID.generate(timestamp)
|
||||
|
||||
Ash.Changeset.force_change_attribute(changeset, :id, ulid)
|
||||
Ash.Changeset.force_change_attribute(changeset, :id, ulid)
|
||||
else
|
||||
changeset
|
||||
end
|
||||
end)
|
||||
|> maybe_destroy_balances(context)
|
||||
|> Ash.Changeset.after_action(fn changeset, result ->
|
||||
|
@ -42,6 +43,9 @@ defmodule AshDoubleEntry.Transfer.Changes.VerifyTransfer do
|
|||
to_account_id = Ash.Changeset.get_attribute(changeset, :to_account_id)
|
||||
amount = Ash.Changeset.get_attribute(changeset, :amount)
|
||||
|
||||
amount_delta =
|
||||
Money.sub!(amount, changeset.data.amount || Money.new!(0, amount.currency))
|
||||
|
||||
accounts =
|
||||
changeset.resource
|
||||
|> AshDoubleEntry.Transfer.Info.transfer_account_resource!()
|
||||
|
@ -56,11 +60,14 @@ defmodule AshDoubleEntry.Transfer.Changes.VerifyTransfer do
|
|||
new_from_account_balance =
|
||||
Money.sub!(
|
||||
from_account.balance_as_of_ulid || Money.new!(0, from_account.currency),
|
||||
amount
|
||||
amount_delta
|
||||
)
|
||||
|
||||
new_to_account_balance =
|
||||
Money.add!(to_account.balance_as_of_ulid || Money.new!(0, to_account.currency), amount)
|
||||
Money.add!(
|
||||
to_account.balance_as_of_ulid || Money.new!(0, to_account.currency),
|
||||
amount_delta
|
||||
)
|
||||
|
||||
unless changeset.action.type == :destroy do
|
||||
changeset.resource
|
||||
|
@ -102,13 +109,13 @@ defmodule AshDoubleEntry.Transfer.Changes.VerifyTransfer do
|
|||
%{
|
||||
account_id: balance.account_id,
|
||||
transfer_id: balance.transfer_id,
|
||||
balance: Money.sub!(balance.balance, amount)
|
||||
balance: Money.sub!(balance.balance, amount_delta)
|
||||
}
|
||||
else
|
||||
%{
|
||||
account_id: balance.account_id,
|
||||
transfer_id: balance.transfer_id,
|
||||
balance: Money.add!(balance.balance, amount)
|
||||
balance: Money.add!(balance.balance, amount_delta)
|
||||
}
|
||||
end
|
||||
end)
|
||||
|
|
|
@ -33,7 +33,7 @@ defmodule AshDoubleEntryTest do
|
|||
end
|
||||
|
||||
actions do
|
||||
defaults [:destroy]
|
||||
defaults [:destroy, :update]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -190,6 +190,38 @@ defmodule AshDoubleEntryTest do
|
|||
)
|
||||
end
|
||||
|
||||
test "updating transfer's amount update the balances accordingly" do
|
||||
account_one =
|
||||
Account
|
||||
|> Ash.Changeset.for_create(:open, %{identifier: "account_one", currency: "USD"})
|
||||
|> Api.create!()
|
||||
|
||||
account_two =
|
||||
Account
|
||||
|> Ash.Changeset.for_create(:open, %{identifier: "account_two", currency: "USD"})
|
||||
|> Api.create!()
|
||||
|
||||
Transfer
|
||||
|> Ash.Changeset.for_create(:transfer, %{
|
||||
amount: Money.new!(:USD, 20),
|
||||
from_account_id: account_one.id,
|
||||
to_account_id: account_two.id
|
||||
})
|
||||
|> Api.create!()
|
||||
|> Ash.Changeset.for_update(:update, %{amount: Money.new!(:USD, 10)})
|
||||
|> Api.update!()
|
||||
|
||||
assert Money.equal?(
|
||||
Api.load!(account_one, :balance_as_of).balance_as_of,
|
||||
Money.new!(:USD, -10)
|
||||
)
|
||||
|
||||
assert Money.equal?(
|
||||
Api.load!(account_two, :balance_as_of).balance_as_of,
|
||||
Money.new!(:USD, 10)
|
||||
)
|
||||
end
|
||||
|
||||
test "balances can be validated" do
|
||||
account_one =
|
||||
Account
|
||||
|
|
Loading…
Reference in a new issue