DoubleEntryLedger.Entryable protocol (double_entry_ledger v0.4.0)
View SourceProtocol defining helper functions for working with entry data in the Double Entry Ledger system.
This protocol provides a consistent interface for operations on different entry types,
allowing the same functions to work with both persisted Entry structs and entries still
in Ecto.Changeset form. It abstracts away implementation details so that higher-level
accounting logic can focus on business rules rather than data structure concerns.
Key Functions
debit_sum/2- Accumulates the sum of debit entriescredit_sum/2- Accumulates the sum of credit entriesuuid/1- Retrieves the account UUID associated with the entrycurrency/1- Retrieves the currency of the entry
Implementations
The protocol is implemented for:
Entry- For working with persisted entry recordsEcto.Changeset- For working with entries still being validated
Usage Examples
The protocol enables generic functions that can operate on collections of mixed entry types:
defmodule DoubleEntryLedger.TransactionValidator do
alias DoubleEntryLedger.Entryable
# Works with both Entry structs and changesets
def balance_entries?(entries) do
debit_sum = Enum.reduce(entries, 0, &Entryable.debit_sum/2)
credit_sum = Enum.reduce(entries, 0, &Entryable.credit_sum/2)
debit_sum == credit_sum
end
# Group entries by currency
def group_by_currency(entries) do
Enum.group_by(entries, &Entryable.currency/1)
end
end
Summary
Functions
Returns the sum of credit entries.
Retrieves the currency of the entry.
Returns the sum of debit entries.
Retrieves the UUID of the entry.
Types
@type t() :: term()
All the types that implement this protocol.
Functions
Returns the sum of credit entries.
Accumulates the amount of entries with type :credit into the accumulator.
Examples
# Using with Entry struct
iex> alias DoubleEntryLedger.Entry
iex> alias DoubleEntryLedger.Entryable
iex> credit_entry = %Entry{type: :credit, value: %{amount: 500, currency: :USD}}
iex> Entryable.credit_sum(credit_entry, 100)
600
iex> debit_entry = %Entry{type: :debit, value: %{amount: 500, currency: :USD}}
iex> Entryable.credit_sum(debit_entry, 100)
100
# Using with Changeset
iex> alias DoubleEntryLedger.Entry
iex> alias DoubleEntryLedger.Entryable
iex> alias Ecto.Changeset
iex> changeset = Changeset.change(%Entry{}, %{type: :credit, value: %{amount: 500, currency: :USD}})
iex> Entryable.credit_sum(changeset, 100)
600
Retrieves the currency of the entry.
Examples
# Using with Entry struct
iex> alias DoubleEntryLedger.Entry
iex> alias DoubleEntryLedger.Entryable
iex> entry = %Entry{value: %{amount: 500, currency: :USD}}
iex> Entryable.currency(entry)
:USD
# Using with Changeset
iex> alias DoubleEntryLedger.Entry
iex> alias DoubleEntryLedger.Entryable
iex> alias Ecto.Changeset
iex> changeset = Changeset.change(%Entry{}, %{value: %{amount: 500, currency: :USD}})
iex> Entryable.currency(changeset)
:USD
Returns the sum of debit entries.
Accumulates the amount of entries with type :debit into the accumulator.
Examples
# Using with Entry struct
iex> alias DoubleEntryLedger.Entry
iex> alias DoubleEntryLedger.Entryable
iex> debit_entry = %Entry{type: :debit, value: %{amount: 500, currency: :USD}}
iex> Entryable.debit_sum(debit_entry, 100)
600
iex> credit_entry = %Entry{type: :credit, value: %{amount: 500, currency: :USD}}
iex> Entryable.debit_sum(credit_entry, 100)
100
# Using with Changeset
iex> alias DoubleEntryLedger.Entry
iex> alias DoubleEntryLedger.Entryable
iex> alias Ecto.Changeset
iex> changeset = Changeset.change(%Entry{}, %{type: :debit, value: %{amount: 500, currency: :USD}})
iex> Entryable.debit_sum(changeset, 100)
600
Retrieves the UUID of the entry.
Examples
# Using with Entry struct
iex> alias DoubleEntryLedger.Entry
iex> alias DoubleEntryLedger.Entryable
iex> entry = %Entry{account_id: "550e8400-e29b-41d4-a716-446655440000"}
iex> Entryable.uuid(entry)
"550e8400-e29b-41d4-a716-446655440000"
# Using with Changeset
iex> alias DoubleEntryLedger.Entry
iex> alias DoubleEntryLedger.Entryable
iex> alias Ecto.Changeset
iex> changeset = Changeset.change(%Entry{}, %{account_id: "550e8400-e29b-41d4-a716-446655440000"})
iex> Entryable.uuid(changeset)
"550e8400-e29b-41d4-a716-446655440000"