Skip to main content

Overview

The Account class represents a single accounting account in the system. It maintains a balance, tracks entries, and supports optimistic locking for concurrent updates. Accounts are classified by type (ASSET, LIABILITY, EXPENSE, REVENUE, OFF_BALANCE) and accumulate entries through transactions. Package: com.softwarearchetypes.accounting Access: Package-private class (accessed through AccountingFacade)

Constructors

Primary Constructor

Account(
    AccountId accountId,
    AccountType type,
    AccountName name,
    Money balance,
    Version version
)
accountId
AccountId
required
Unique identifier for the account (must not be null)
type
AccountType
required
Account classification: ASSET, LIABILITY, EXPENSE, REVENUE, or OFF_BALANCE
name
AccountName
required
Human-readable account name
balance
Money
Initial balance (defaults to zero PLN if null)
version
Version
required
Version for optimistic locking

Simplified Constructors

Account(AccountId accountId, AccountType type, AccountName name)
Account(AccountId accountId, AccountType type, AccountName name, Version version)
These constructors default the balance to zero PLN and version to initial if not specified.

Properties

id

Returns the unique account identifier.
AccountId id()
AccountId
AccountId
The account’s unique identifier

name

Returns the account name as a string.
String name()
String
String
Human-readable account name

type

Returns the account type classification.
AccountType type()
AccountType
AccountType
Account classification (ASSET, LIABILITY, EXPENSE, REVENUE, OFF_BALANCE)

balance

Returns the current account balance.
Money balance()
Money
Money
Current balance reflecting all entries
Note: Balance is calculated by summing all entry amounts. Credits add positive amounts, debits add negative amounts.

version

Returns the version for optimistic locking.
Version version()
Version
Version
Current version number for concurrency control

entries

Returns a copy of the account’s entries.
Entries entries()
Entries
Entries
Copy of new entries added to this account (not all historical entries when loaded from database)
Implementation Note: To avoid loading all historical entries when retrieving accounts from the database, only new entries added during the current session are tracked in memory. Historical queries should use AccountView through AccountingFacade.

Methods

addEntry

Adds a single entry to the account and updates the balance.
void addEntry(Entry entry)
entry
Entry
required
The entry to add (AccountCredited or AccountDebited)
Side Effects:
  • Updates the account balance
  • Records a pending domain event (CreditEntryRegistered or DebitEntryRegistered)
  • Adds entry to the newEntries collection

addEntries

Adds multiple entries to the account and updates the balance.
void addEntries(List<Entry> newEntries)
newEntries
List<Entry>
required
List of entries to add
Side Effects:
  • Updates the account balance for each entry
  • Records pending domain events for each entry
  • Adds all entries to the newEntries collection

Event Management

getPendingEvents

Retrieves domain events pending publication.
List<AccountingEvent> getPendingEvents()
List
List<AccountingEvent>
Immutable copy of pending events (CreditEntryRegistered, DebitEntryRegistered)

clearPendingEvents

Clears all pending events after publication.
void clearPendingEvents()
Usage: Called by AccountingFacade after successfully publishing events.

Account Types

The AccountType enum defines the classification and behavior of accounts:
public enum AccountType {
    ASSET(true),
    OFF_BALANCE(false),
    EXPENSE(true),
    LIABILITY(true),
    REVENUE(true)
}

ASSET

Represents owned economic resources with future value.
doubleEntryBookingEnabled
boolean
true - Must balance in transactions
Examples: Cash, accounts receivable, inventory

LIABILITY

Represents obligations or debts owed by the entity.
doubleEntryBookingEnabled
boolean
true - Must balance in transactions
Examples: Accounts payable, loans, accrued expenses

REVENUE

Represents inflows from sales, services, or income-generating activities.
doubleEntryBookingEnabled
boolean
true - Must balance in transactions
Examples: Sales revenue, service fees, interest income

EXPENSE

Represents outflows for operations, costs, or losses.
doubleEntryBookingEnabled
boolean
true - Must balance in transactions
Examples: Operational costs, write-offs, penalties, losses

OFF_BALANCE

Represents tracking accounts that don’t affect financial statements.
doubleEntryBookingEnabled
boolean
false - Does not require balancing in transactions
Examples: Collateral tracking, guarantees, projected values

AccountId

public record AccountId(UUID uuid) {
    public static AccountId generate()
    public static AccountId of(UUID uuid)
}

AccountName

Value object wrapping the account name string.

AccountView

Read model for querying account data:
public record AccountView(
    AccountId id,
    String name,
    String type,
    Money balance,
    List<EntryView> entries
) {
    Money balanceAsOf(Instant time)
}
Usage: Use AccountingFacade.findAccount() to retrieve complete account information including all historical entries.

Example Usage

Creating an Account

// Through AccountingFacade
CreateAccount request = CreateAccount.generateAssetAccount(
    AccountId.generate(),
    "Customer Receivables"
);
Result<String, AccountId> result = facade.createAccount(request);

Querying Account Details

// Get current balance
Optional<Money> balance = facade.balance(accountId);

// Get complete account view
Optional<AccountView> accountView = facade.findAccount(accountId);
accountView.ifPresent(view -> {
    System.out.println("Account: " + view.name());
    System.out.println("Balance: " + view.balance());
    System.out.println("Entries: " + view.entries().size());
});

// Get historical balance
Instant lastYear = Instant.now().minus(365, ChronoUnit.DAYS);
Optional<Money> historicalBalance = facade.balanceAsOf(accountId, lastYear);

Concurrency and Locking

Accounts use optimistic locking through the Version field. When multiple transactions attempt to update the same account concurrently:
  1. Each transaction reads the account with its current version
  2. The transaction adds entries and executes
  3. When saving, the repository checks if the version has changed
  4. If the version changed, the transaction fails and must retry
This ensures consistency without pessimistic locks.

Build docs developers (and LLMs) love