# `Logistiki.Accounting.Posting`
[🔗](https://github.com/thanos/logistiki/blob/v0.1.0/lib/logistiki/accounting/posting.ex#L1)

A posting is a single debit or credit leg of a journal.

Amounts are always positive; the `debit_credit` field encodes direction.
Postings only target leaf virtual accounts. Once a journal is posted, its
postings are immutable.

## Fields

  * `id` — `integer()` — primary key
  * `journal_id` — `integer()` — FK to `journals`
  * `virtual_account_id` — `integer() | nil` — FK to `virtual_accounts`
  * `account_code` — `String.t()` — denormalized for audit readability (e.g.
    `"ASSETS:CASH:USD:NOSTRO"`)
  * `debit_credit` — `String.t()` — `"debit"` or `"credit"`
  * `amount` — `Decimal.t()` — always positive (e.g. `Decimal.new("1000.00")`)
  * `currency` — `String.t()` — e.g. `"USD"`
  * `memo` — `String.t() | nil`
  * `sequence` — `integer()` — ordering within the journal (1-based)
  * `metadata` — `map()` — includes the symbolic `role` (e.g.
    `%{"role" => "cash_account"}`)
  * `inserted_at` / `updated_at` — `DateTime.t()`

## Rules

  * amount is positive; direction encodes sign
  * `debit_credit` is `debit` or `credit`
  * the posting account must be a leaf, active, posting-allowed account
  * the journal must balance per currency
  * postings are immutable once the journal is posted
  * `account_code` is denormalized for audit readability but
    `virtual_account_id` remains canonical

## Example

    %Logistiki.Accounting.Posting{
      id: 1,
      journal_id: 1,
      virtual_account_id: 10,
      account_code: "ASSETS:CASH:USD:NOSTRO",
      debit_credit: "debit",
      amount: Decimal.new("1000.00"),
      currency: "USD",
      sequence: 1,
      metadata: %{"role" => "cash_account"}
    }

# `t`

```elixir
@type t() :: %Logistiki.Accounting.Posting{
  __meta__: term(),
  account_code: String.t() | nil,
  amount: Decimal.t() | nil,
  currency: String.t() | nil,
  debit_credit: String.t() | nil,
  id: integer() | nil,
  inserted_at: DateTime.t() | nil,
  journal: term(),
  journal_id: integer() | nil,
  memo: String.t() | nil,
  metadata: map() | nil,
  sequence: integer() | nil,
  updated_at: DateTime.t() | nil,
  virtual_account: term(),
  virtual_account_id: integer() | nil
}
```

The `Posting` struct type — a single debit or credit leg of a journal.

## Fields

  * `id` — `integer() | nil` — primary key (e.g. `1`)
  * `journal_id` — `integer() | nil` — FK to `journals` (e.g. `1`)
  * `virtual_account_id` — `integer() | nil` — FK to `virtual_accounts` (e.g. `10`)
  * `account_code` — `String.t() | nil` — denormalized (e.g. `"ASSETS:CASH:USD:NOSTRO"`)
  * `debit_credit` — `String.t() | nil` — `"debit"` or `"credit"`
  * `amount` — `Decimal.t() | nil` — always positive (e.g. `Decimal.new("1000.00")`)
  * `currency` — `String.t() | nil` — e.g. `"USD"`
  * `memo` — `String.t() | nil` — optional memo
  * `sequence` — `integer() | nil` — ordering within the journal
  * `metadata` — `map() | nil` — includes the symbolic role
  * `inserted_at` — `DateTime.t() | nil`
  * `updated_at` — `DateTime.t() | nil`

## Example

    %Logistiki.Accounting.Posting{
      id: 1, journal_id: 1, virtual_account_id: 10,
      account_code: "ASSETS:CASH:USD:NOSTRO", debit_credit: "debit",
      amount: Decimal.new("1000.00"), currency: "USD", sequence: 1
    }

# `credit?`
*since 0.1.0* 

```elixir
@spec credit?(t()) :: boolean()
```

True for a credit posting.

## Arguments

  * `posting` — `%__MODULE__{}` or any term.

## Returns

  * `boolean()` — `true` when `debit_credit == "credit"`.

## Examples

    iex> Logistiki.Accounting.Posting.credit?(%Logistiki.Accounting.Posting{debit_credit: "credit"})
    true

# `debit?`
*since 0.1.0* 

```elixir
@spec debit?(t()) :: boolean()
```

True for a debit posting.

## Arguments

  * `posting` — `%__MODULE__{}` or any term.

## Returns

  * `boolean()` — `true` when `debit_credit == "debit"`.

## Examples

    iex> Logistiki.Accounting.Posting.debit?(%Logistiki.Accounting.Posting{debit_credit: "debit"})
    true
    iex> Logistiki.Accounting.Posting.debit?(%Logistiki.Accounting.Posting{debit_credit: "credit"})
    false

# `directions`
*since 0.1.0* 

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

Returns the list of allowed posting directions as atoms.

## Returns

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

## Examples

    iex> Logistiki.Accounting.Posting.directions()
    [:debit, :credit]

# `signed_amount`
*since 0.1.0* 

```elixir
@spec signed_amount(t()) :: Decimal.t()
```

Returns the signed amount: positive for debit, negative for credit.

## Arguments

  * `posting` — `%__MODULE__{}`.

## Returns

  * `Decimal.t()` — `amount` for debit, `-amount` for credit.

## Examples

    iex> Logistiki.Accounting.Posting.signed_amount(%Logistiki.Accounting.Posting{amount: Decimal.new("100"), debit_credit: "debit"})
    Decimal.new("100")
    iex> Logistiki.Accounting.Posting.signed_amount(%Logistiki.Accounting.Posting{amount: Decimal.new("100"), debit_credit: "credit"})
    Decimal.new("-100")

---

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