DoubleEntryLedger.Workers.CommandWorker.CreateAccountCommandMapNoSaveOnError (double_entry_ledger v0.2.0)

View Source

Processes AccountCommandMap for creating new accounts in the double-entry ledger system.

This worker handles the creation of accounts based on validated AccountCommandMap data. It coordinates the creation of both the Command record (for audit trail) and the Account record (the actual ledger account) within a single database transaction.

Unlike standard command processors, this module does not persist error states to the database. Instead, it returns validation errors as changesets for client handling, making it suitable for scenarios where error persistence should be managed externally.

Processing Flow

  1. Command Creation: Creates a Command record from the AccountCommandMap for audit purposes
  2. Account Creation: Creates the Account record using the payload data
  3. Command Completion: Marks the command as processed upon successful account creation
  4. Linking: Creates a link between the command and the created account for traceability

Error Handling

The module provides detailed error handling and logging:

  • Command validation errors are mapped back to AccountCommandMap changesets
  • Account validation errors are propagated to the command map payload
  • All processing steps are logged with appropriate trace information
  • Database transaction ensures atomicity (all-or-nothing)
  • Errors are returned as changesets rather than persisted to the database

Key Features

  • Transactional Safety: Uses Ecto.Multi for atomic operations
  • Error Propagation: Maps validation errors back to appropriate changeset structures
  • Audit Trail: Creates command records for all account creation attempts
  • Traceability: Links commands to created accounts for audit purposes
  • No Error Persistence: Returns error changesets without database persistence

Supported Actions

Currently supports:

  • :create_account - Creates a new account from AccountCommandMap payload

Summary

Functions

Processes an AccountCommandMap to create a new account in the ledger system.

Functions

process(command_map)

Processes an AccountCommandMap to create a new account in the ledger system.

This function orchestrates the creation of both a Command record (for audit trail) and an Account record within a single database transaction. Upon successful completion, the command is marked as processed and linked to the created account.

Parameters

  • command_map: AccountCommandMap struct containing validated account creation data. Must have :create_account action.

Returns

  • {:ok, account, command} - Success tuple containing the created Account and Command
  • {:error, changeset} - AccountCommandMap changeset with validation errors when command or account creation fails
  • {:error, message} - String error message for unexpected failures

Transaction Steps

  1. Creates Command record from AccountCommandMap
  2. Creates Account record from payload data
  3. Marks Command as processed
  4. Creates Command-Account link for traceability

Error Mapping

  • Command validation errors → AccountCommandMap changeset with command-level errors
  • Account validation errors → AccountCommandMap changeset with payload-level errors
  • Other failures → String error message with details

Examples

# Successful account creation
iex> {:ok, instance} = InstanceStore.create(%{address: "Main:Instance"})
iex> command_map = %AccountCommandMap{
...>   action: :create_account,
...>   source: "test_suite",
...>   instance_address: instance.address,
...>   payload: %AccountData{
...>     name: "Cash Account",
...>     address: "account:main",
...>     type: :asset,
...>     currency: :USD
...>   }
...> }
iex> {:ok, account, event} = CreateAccountCommandMapNoSaveOnError.process(command_map)
iex> is_struct(account, Account) and account.name == "Cash Account" and is_struct(event, Command) and event.command_queue_item.status == :processed
true

iex> {:ok, instance} = InstanceStore.create(%{address: "Main:Instance"})
iex> invalid_command_map = %AccountCommandMap{
...>   action: :create_account,
...>   source: "test_suite",
...>   instance_address: instance.address,
...>   payload: %AccountData{name: "", type: nil}  # missing required fields
...> }
iex> {:error, changeset} = CreateAccountCommandMapNoSaveOnError.process(invalid_command_map)
iex> changeset.valid?
false