View Source Bookk.Ledger (bookk v0.1.3)
A ledger is a book that holds accounts. Traditionally, ledgers would also hold the journal entries that changed the accounts but, in this library, persisting those journal entries is considered off scope. You may persist state the way the best fits your needs.
Related
Summary
Functions
Checks whether the ledger is balanced.
Get an account from the ledger by its Bookk.AccountHead
. If the
account doesn't exist yet, then an account will be returned with
empty state.
Creates a new Bookk.Ledger
from its name and, optionally, a list
of Bookk.Account
.
Posts a Bookk.JournalEntry
to a ledger. This means that the
balance change described in each operation of the journal entry will
be applied to their respective accounts of the ledger. If there's a
change to an account that doesn't exist yet, then the account is
first created.
Types
@type t() :: %Bookk.Ledger{ accounts_by_name: %{required(name :: String.t()) => Bookk.Account.t()}, name: String.t() }
The struct that represents a ledger.
Fields
name
: the name of the ledger;accounts_by_name
: a map of the accounts known by the ledger, grouped by their name.
Functions
Checks whether the ledger is balanced.
A ledger is considered balance when the some 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
Is balanced when the ledger is empty:
iex> Bookk.Ledger.new("acme")
iex> |> Bookk.Ledger.balanced?()
true
Is balanced when the sum of debit accounts balances is equal the sum of credit accounts balances:
iex> ledger = Bookk.Ledger.new("acme")
iex> cash = fixture_account_head(:cash)
iex> deposits = fixture_account_head(:deposits)
iex>
iex> journal_entry = %Bookk.JournalEntry{
iex> operations: [
iex> debit(cash, 50_00),
iex> credit(deposits, 50_00)
iex> ]
iex> }
iex>
iex> Bookk.Ledger.post(ledger, journal_entry)
iex> |> Bookk.Ledger.balanced?()
true
Is unbalanced when the sum of debit accounts balances isn't equal the sum of credit accounts balances:
iex> ledger = Bookk.Ledger.new("acme")
iex> cash = fixture_account_head(:cash)
iex>
iex> journal_entry = %Bookk.JournalEntry{
iex> operations: [
iex> debit(cash, 50_00)
iex> ]
iex> }
iex>
iex> Bookk.Ledger.post(ledger, journal_entry)
iex> |> Bookk.Ledger.balanced?()
false
@spec get_account(t(), Bookk.AccountHead.t()) :: Bookk.Account.t()
Get an account from the ledger by its Bookk.AccountHead
. If the
account doesn't exist yet, then an account will be returned with
empty state.
Examples
Returns the account when it exists in the ledger:
iex> ledger = %Bookk.Ledger{
iex> name: "acme",
iex> accounts_by_name: %{
iex> "cash/CA" => %Bookk.Account{
iex> head: fixture_account_head(:cash),
iex> balance: 25_00
iex> }
iex> }
iex> }
iex>
iex> Bookk.Ledger.get_account(ledger, fixture_account_head(:cash))
%Bookk.Account{
head: fixture_account_head(:cash),
balance: 25_00
}
Returns an empty account when the it doesn't exist in the ledger:
iex> Bookk.Ledger.new("acme")
iex> |> Bookk.Ledger.get_account(fixture_account_head(:cash))
%Bookk.Account{
head: fixture_account_head(:cash),
balance: 0
}
@spec new(name :: String.t(), [Bookk.Account.t()]) :: t()
Creates a new Bookk.Ledger
from its name and, optionally, a list
of Bookk.Account
.
@spec post(t(), Bookk.JournalEntry.t()) :: t()
Posts a Bookk.JournalEntry
to a ledger. This means that the
balance change described in each operation of the journal entry will
be applied to their respective accounts of the ledger. If there's a
change to an account that doesn't exist yet, then the account is
first created.
Examples
When account doesn't exist then it gets created:
iex> ledger = Bookk.Ledger.new("acme")
iex>
iex> cash = fixture_account_head(:cash)
iex> deposits = fixture_account_head(:deposits)
iex>
iex> journal_entry = %Bookk.JournalEntry{
iex> operations: [
iex> debit(cash, 50_00),
iex> credit(deposits, 50_00)
iex> ]
iex> }
iex>
iex> updated_ledger = Bookk.Ledger.post(ledger, journal_entry)
iex>
iex> %Bookk.Account{balance: 50_00} = Bookk.Ledger.get_account(updated_ledger, cash)
iex> %Bookk.Account{balance: 50_00} = Bookk.Ledger.get_account(updated_ledger, deposits)
When account exists then it gets updated:
iex> ledger = Bookk.Ledger.new("acme")
iex>
iex> cash = fixture_account_head(:cash)
iex> deposits = fixture_account_head(:deposits)
iex>
iex> journal_entry = %Bookk.JournalEntry{
iex> operations: [
iex> debit(cash, 50_00),
iex> credit(deposits, 50_00)
iex> ]
iex> }
iex>
iex> updated_ledger =
iex> ledger
iex> |> Bookk.Ledger.post(journal_entry)
iex> |> Bookk.Ledger.post(journal_entry) # post twice
iex>
iex> %Bookk.Account{balance: 100_00} = Bookk.Ledger.get_account(updated_ledger, cash)
iex> %Bookk.Account{balance: 100_00} = Bookk.Ledger.get_account(updated_ledger, deposits)