# `Logistiki.VirtualAccounts.VirtualAccount`
[🔗](https://github.com/thanos/logistiki/blob/v0.1.0/lib/logistiki/virtual_accounts/virtual_account.ex#L1)

A hierarchical accounting account. Virtual accounts are not balances; balances
are derived from postings. Parent accounts aggregate children.

## Fields

  * `id` — `integer()` — primary key (e.g. `10`)
  * `parent_id` — `integer() | nil` — self-reference; `nil` for roots (e.g. `9` or `nil`)
  * `code` — `String.t()` — unique, stable, human-readable (colon-separated, e.g. `"ASSETS:CASH:USD:NOSTRO"`)
  * `name` — `String.t()` — display name (e.g. `"Nostro USD"`)
  * `account_type` — `String.t()` — one of `account_types/0` (e.g. `"asset"`, `"liability"`, `"client"`)
  * `currency` — `String.t() | nil` — required for posting accounts; `nil` for aggregation accounts (e.g. `"USD"` or `nil`)
  * `status` — `String.t()` — one of `statuses/0` (default `"active"`, e.g. `"frozen"`)
  * `posting_allowed` — `boolean()` — only leaf accounts may allow postings (default `false`)
  * `normal_balance` — `String.t() | nil` — `"debit"` or `"credit"` (e.g. `"debit"`)
  * `external_id` — `String.t() | nil` — unique external reference (e.g. `"core_001"`)
  * `metadata` — `map()` — extensible key/value store (default `%{}`, e.g. `%{"iban" => "GB29..."}`)
  * `inserted_at` — `DateTime.t() | nil` — set by Ecto (e.g. `~U[2026-07-07 12:00:00Z]`)
  * `updated_at` — `DateTime.t() | nil` — set by Ecto

## Associations

  * `parent` — `belongs_to` `__MODULE__` — the parent account (via `parent_id`)
  * `children` — `has_many` `__MODULE__` — direct child accounts

## Example

    %Logistiki.VirtualAccounts.VirtualAccount{
      id: 10,
      parent_id: 9,
      code: "ASSETS:CASH:USD:NOSTRO",
      name: "Nostro USD",
      account_type: "asset",
      currency: "USD",
      posting_allowed: true,
      normal_balance: "debit",
      status: "active"
    }

# `t`

```elixir
@type t() :: %Logistiki.VirtualAccounts.VirtualAccount{
  __meta__: term(),
  account_type: String.t() | nil,
  children: term(),
  code: String.t() | nil,
  currency: String.t() | nil,
  external_id: String.t() | nil,
  id: integer() | nil,
  inserted_at: DateTime.t() | nil,
  metadata: map() | nil,
  name: String.t() | nil,
  normal_balance: String.t() | nil,
  parent: term(),
  parent_id: integer() | nil,
  posting_allowed: boolean() | nil,
  status: String.t() | nil,
  updated_at: DateTime.t() | nil
}
```

The `VirtualAccount` struct type.

Represents a hierarchical accounting account. Balances are derived from
postings — the account itself is not a balance.

## Fields

  * `id` — `integer() | nil` — primary key (e.g. `10`)
  * `parent_id` — `integer() | nil` — parent account id; `nil` for roots
  * `code` — `String.t() | nil` — unique code (e.g. `"ASSETS:CASH:USD:NOSTRO"`)
  * `name` — `String.t() | nil` — display name (e.g. `"Nostro USD"`)
  * `account_type` — `String.t() | nil` — e.g. `"asset"`, `"client"`
  * `currency` — `String.t() | nil` — e.g. `"USD"` or `nil` for aggregation accounts
  * `status` — `String.t() | nil` — e.g. `"active"`, `"frozen"`
  * `posting_allowed` — `boolean() | nil` — whether postings target this account
  * `normal_balance` — `String.t() | nil` — `"debit"` or `"credit"`
  * `external_id` — `String.t() | nil` — unique external reference
  * `metadata` — `map() | nil` — extensible metadata
  * `inserted_at` — `DateTime.t() | nil`
  * `updated_at` — `DateTime.t() | nil`

## Example

    %Logistiki.VirtualAccounts.VirtualAccount{
      id: 10, parent_id: 9, code: "ASSETS:CASH:USD:NOSTRO",
      name: "Nostro USD", account_type: "asset", currency: "USD",
      posting_allowed: true, normal_balance: "debit", status: "active"
    }

# `account_types`
*since 0.1.0* 

```elixir
@spec account_types() :: [atom(), ...]
```

Returns the list of allowed account types as atoms.

## Returns

  * `[atom()]` — `[:asset, :liability, :equity, :income, :expense,
    :client, :settlement, :suspense, :fee, :tax, :clearing]`

## Examples

    iex> :asset in Logistiki.VirtualAccounts.VirtualAccount.account_types()
    true

# `normal_balances`
*since 0.1.0* 

```elixir
@spec normal_balances() :: [atom(), ...]
```

Returns the list of allowed normal-balance values as atoms.

## Returns

  * `[atom()]` — `[:debit, :credit]`

## Examples

    iex> Logistiki.VirtualAccounts.VirtualAccount.normal_balances()
    [:debit, :credit]

# `statuses`
*since 0.1.0* 

```elixir
@spec statuses() :: [atom(), ...]
```

Returns the list of allowed account statuses as atoms.

## Returns

  * `[atom()]` — `[:active, :inactive, :frozen, :closed]`

## Examples

    iex> Logistiki.VirtualAccounts.VirtualAccount.statuses()
    [:active, :inactive, :frozen, :closed]

---

*Consult [api-reference.md](api-reference.md) for complete listing*
