A state struct that holds multiple ledgers. It's considered "naive" because it doesn't hold any information regarding the events that led to the current state.
Related
Summary
Functions
Checks whether the state is balanced.
Calculates a Bookk.InterledgerEntry represending the diff between
two Bookk.NaiveState where, if such interledger entry were to be
posted to state "a", it would become equal to state "b".
Checks wether the given state is empty (no ledgers with balance).
Get's a ledger from the state by its id. If the ledger doesn't exist in the state yet, then a new empty ledger will be returned.
Merges a set of states into one.
Merges two states into one.
Produces a new state struct from a set of ledgers.
Posts a Bookk.InterledgerEntry to the state, appling changes in
balance to multiple accounts accross multiple ledgers.
Types
@type t() :: %Bookk.NaiveState{ ledgers_by_id: %{required(id :: String.t()) => Bookk.Ledger.t()} }
The struct representing a naive state.
Fields
ledgers_by_id: the ledgers known by the state, grouped by their id.
Functions
Checks whether the state is balanced.
A state is considered balance when the sum of balance from its debit accounts is equal the sum of balance from its credit accounts. You know if an account is a "debit account" or a "credit account" by the natural balance of its class.
See Bookk.AccountClass for more information on natural balance.
Examples
Balanced:
iex> state = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(25)),
iex> Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(25))
iex> ])
iex> ])
iex>
iex> Bookk.NaiveState.balanced?(state)
trueUnbalanced:
iex> state = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(25)),
iex> Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(10))
iex> ])
iex> ])
iex>
iex> Bookk.NaiveState.balanced?(state)
false
@spec diff(a :: t(), b :: t()) :: Bookk.InterledgerEntry.t()
Calculates a Bookk.InterledgerEntry represending the diff between
two Bookk.NaiveState where, if such interledger entry were to be
posted to state "a", it would become equal to state "b".
Examples
iex> a = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(25)),
iex> Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(25))
iex> ])
iex> ])
iex>
iex> b = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(100)),
iex> Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(25)),
iex> Bookk.Account.new(fixture_account_head({:unspent_cash, {:user, "12345"}}), Decimal.new(75))
iex> ]),
iex> Bookk.Ledger.new("foo", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(75)),
iex> Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(75))
iex> ])
iex> ])
iex>
iex> Bookk.NaiveState.diff(a, b)
Bookk.InterledgerEntry.new([
{"acme", Bookk.JournalEntry.new([
debit(fixture_account_head(:cash), Decimal.new(75)),
credit(fixture_account_head({:unspent_cash, {:user, "12345"}}), Decimal.new(75))
])},
{"foo", Bookk.JournalEntry.new([
debit(fixture_account_head(:cash), Decimal.new(75)),
credit(fixture_account_head(:deposits), Decimal.new(75))
])}
])
Checks wether the given state is empty (no ledgers with balance).
Examples
iex> Bookk.NaiveState.new()
iex> |> Bookk.NaiveState.empty?()
true
iex> state = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(0)),
iex> Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(0))
iex> ])
iex> ])
iex>
iex> Bookk.NaiveState.empty?(state)
true
iex> state = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(10)),
iex> Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(10))
iex> ])
iex> ])
iex>
iex> Bookk.NaiveState.empty?(state)
false
@spec get_ledger(t(), String.t()) :: Bookk.Ledger.t()
Get's a ledger from the state by its id. If the ledger doesn't exist in the state yet, then a new empty ledger will be returned.
Examples
Returns an empty ledger when requested ledger doesn't exist in state:
iex> Bookk.NaiveState.get_ledger(%Bookk.NaiveState{}, "acme")
%Bookk.Ledger{id: "acme"}Returns the ledger when it exists in state:
iex> state = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("foo", [
iex> Bookk.Account.new(fixture_account_head(:cash))
iex> ])
iex> ])
iex>
iex> Bookk.NaiveState.get_ledger(state, "foo")
Bookk.Ledger.new("foo", [
Bookk.Account.new(fixture_account_head(:cash))
])
Merges a set of states into one.
Examples
iex> a = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(5))
iex> ])
iex> ])
iex>
iex> b = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head({:unspent_cash, {:user, "12345"}}), Decimal.new(5))
iex> ]),
iex> Bookk.Ledger.new("user(12345)", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(5)),
iex> Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(5)),
iex> ])
iex> ])
iex>
iex> c = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("foo", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(25)),
iex> Bookk.Account.new(fixture_account_head({:unspent_cash, {:user, "12345"}}), Decimal.new(25))
iex> ])
iex> ])
iex>
iex> Bookk.NaiveState.merge([a, b, c])
Bookk.NaiveState.new([
Bookk.Ledger.new("acme", [
Bookk.Account.new(fixture_account_head(:cash), Decimal.new(5)),
Bookk.Account.new(fixture_account_head({:unspent_cash, {:user, "12345"}}), Decimal.new(5))
]),
Bookk.Ledger.new("foo", [
Bookk.Account.new(fixture_account_head(:cash), Decimal.new(25)),
Bookk.Account.new(fixture_account_head({:unspent_cash, {:user, "12345"}}), Decimal.new(25))
]),
Bookk.Ledger.new("user(12345)", [
Bookk.Account.new(fixture_account_head(:cash), Decimal.new(5)),
Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(5)),
])
])
Merges two states into one.
Examples
iex> a = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(5))
iex> ])
iex> ])
iex>
iex> b = Bookk.NaiveState.new([
iex> Bookk.Ledger.new("acme", [
iex> Bookk.Account.new(fixture_account_head({:unspent_cash, {:user, "12345"}}), Decimal.new(5))
iex> ]),
iex> Bookk.Ledger.new("user(12345)", [
iex> Bookk.Account.new(fixture_account_head(:cash), Decimal.new(5)),
iex> Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(5)),
iex> ])
iex> ])
iex>
iex> Bookk.NaiveState.merge(a, b)
Bookk.NaiveState.new([
Bookk.Ledger.new("acme", [
Bookk.Account.new(fixture_account_head(:cash), Decimal.new(5)),
Bookk.Account.new(fixture_account_head({:unspent_cash, {:user, "12345"}}), Decimal.new(5))
]),
Bookk.Ledger.new("user(12345)", [
Bookk.Account.new(fixture_account_head(:cash), Decimal.new(5)),
Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(5)),
])
])
@spec new([Bookk.Ledger.t()]) :: t()
Produces a new state struct from a set of ledgers.
@spec post(t(), Bookk.InterledgerEntry.t()) :: t()
Posts a Bookk.InterledgerEntry to the state, appling changes in
balance to multiple accounts accross multiple ledgers.
Examples
iex> use Bookk.Notation
iex>
iex> user_id = "123"
iex> deposited_amount = Decimal.new(500)
iex>
iex> journal_entry =
iex> journalize using: DummyChartOfAccounts do
iex> on ledger(:acme) do
iex> debit account(:cash), deposited_amount
iex> credit account({:unspent_cash, {:user, user_id}}), deposited_amount
iex> end
iex>
iex> on ledger({:user, user_id}) do
iex> debit account(:cash), deposited_amount
iex> credit account(:deposits), deposited_amount
iex> end
iex> end
iex>
iex> Bookk.NaiveState.new()
iex> |> Bookk.NaiveState.post(journal_entry)
Bookk.NaiveState.new([
Bookk.Ledger.new("acme", [
Bookk.Account.new(fixture_account_head(:cash), Decimal.new(500)),
Bookk.Account.new(fixture_account_head({:unspent_cash, {:user, "123"}}), Decimal.new(500))
]),
Bookk.Ledger.new("user(123)", [
Bookk.Account.new(fixture_account_head(:cash), Decimal.new(500)),
Bookk.Account.new(fixture_account_head(:deposits), Decimal.new(500))
])
])