DoubleEntryLedger.Workers.CommandWorker.TransactionCommandTransformer (double_entry_ledger v0.1.0)

View Source

Transforms accounting events into ledger operations in the double-entry bookkeeping system.

This module serves as a transformation layer between incoming transaction events and the internal ledger representation. It handles:

  • Converting transaction data to the format required by the ledger system
  • Validating transaction entries for required fields, valid currency, and integer amounts using changeset validation
  • Retrieving relevant accounts for each transaction entry
  • Determining the correct debit/credit classification based on account types
  • Ensuring monetary values are properly formatted

The transformer provides a critical validation step, ensuring that all required accounts exist and that entries are properly structured and valid before they are recorded in the ledger.

Summary

Types

Represents a single ledger entry with account, monetary value, and entry type.

Represents a complete transaction with its entries ready for ledger processing.

Functions

Transforms transaction data into a transaction map suitable for ledger operations.

Types

entry_map()

@type entry_map() :: %{
  account_id: Ecto.UUID.t(),
  value: Money.t(),
  type: DoubleEntryLedger.Types.credit_or_debit()
}

Represents a single ledger entry with account, monetary value, and entry type.

Fields

  • :account_id - UUID of the account associated with this entry
  • :value - Monetary amount as a Money struct (always positive)
  • :type - Either :debit or :credit indicating the entry type

transaction_map()

@type transaction_map() :: %{
  instance_id: Ecto.UUID.t(),
  status: DoubleEntryLedger.Transaction.state(),
  entries: [entry_map()]
}

Represents a complete transaction with its entries ready for ledger processing.

Fields

  • :instance_id - UUID of the instance this transaction belongs to
  • :status - Current state of the transaction (e.g. :pending, :completed)
  • :entries - List of entry maps that make up this transaction

Functions

transaction_data_to_transaction_map(transaction_data, instance_id)

@spec transaction_data_to_transaction_map(
  DoubleEntryLedger.Command.TransactionData.t() | map(),
  Ecto.UUID.t()
) ::
  {:ok, transaction_map()}
  | {:error,
     :no_accounts_found
     | :some_accounts_not_found
     | :no_accounts_and_or_entries_provided
     | :account_entries_mismatch
     | :missing_entry_for_account
     | :invalid_entry_data}

Transforms transaction data into a transaction map suitable for ledger operations.

This function takes incoming transaction data and converts it to the internal format used by the ledger system. It handles both empty transactions (no entries) and transactions with entries. For transactions with entries, it first validates all entries using changeset validation (ensuring required fields, valid currency, and integer amount). If validation passes, it retrieves the associated accounts and maps each entry to the appropriate entry format.

Parameters

  • transaction_data - A TransactionData struct containing transaction information including entries and status
  • instance_id - UUID of the instance associated with the transaction

Returns

  • {:ok, transaction_map} - Successfully transformed and validated transaction data
  • {:error, reason} - Failed to transform data, with reason as an atom (see below)

Error Reasons

  • :invalid_entry_data - One or more entries failed changeset validation (missing/invalid fields, currency, or amount)
  • :no_accounts_found - No accounts found for the given instance and account IDs
  • :some_accounts_not_found - Some, but not all, accounts found for the given IDs
  • :no_accounts_and_or_entries_provided - No accounts or entries provided
  • :account_entries_mismatch - Number of accounts and entries do not match
  • :missing_entry_for_account - An account was found with no matching entry

Examples

iex> transaction_data = %TransactionData{entries: [], status: :pending}
iex> TransactionCommandTransformer.transaction_data_to_transaction_map(transaction_data, "instance-123")
{:ok, %{instance_id: "instance-123", status: :pending}}