# `Beancount.Report`
[🔗](https://github.com/thanos/beancount_ex/blob/v0.6.0/lib/beancount/report.ex#L1)

Higher-level reporting API built on top of `Beancount.query_text/2`.

Each function generates a canned [BQL](https://beancount.github.io/docs/beancount_query_language.html)
query and runs it through the configured engine, returning a neutral
`Beancount.Query.Result`. Reports therefore work against any engine that
implements `c:Beancount.Engine.query/2`.

A `ledger` argument may be either a list of directives (which is rendered
first) or raw `.bean` text.

Examples below use `Beancount.Engine.Elixir` so they run without `bean-query`.
Configure `config :beancount_ex, engine: Beancount.Engine.Elixir` to use these
reports through `Beancount.balances/1` and friends.

# `ledger`

```elixir
@type ledger() :: [Beancount.directive()] | binary()
```

# `result`

```elixir
@type result() :: {:ok, Beancount.Query.Result.t()} | {:error, Beancount.Result.t()}
```

# `balance_sheet`

```elixir
@spec balance_sheet(ledger()) :: result()
```

Balance sheet: balances of Assets, Liabilities and Equity accounts.

## Examples

    iex> Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
    iex> {:ok, %Beancount.Query.Result{}} = Beancount.Report.balance_sheet(Beancount.Report.sample_ledger())

# `balances`

```elixir
@spec balances(ledger()) :: result()
```

Balances for every account.

BQL: `SELECT account, sum(position) AS balance GROUP BY account ORDER BY account`.

## Examples

    iex> Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
    iex> {:ok, result} = Beancount.Report.balances(Beancount.Report.sample_ledger())
    iex> result.columns
    ["account", "balance"]

# `holdings`

```elixir
@spec holdings(ledger()) :: result()
```

Holdings: unit and cost positions held in Asset accounts.

## Examples

    ledger = [
      Beancount.open(~D[2026-01-01], "Assets:Stocks", ["AAPL"], booking: "FIFO"),
      Beancount.open(~D[2026-01-01], "Assets:Cash", ["USD"]),
      Beancount.open(~D[2026-01-01], "Equity:Opening", ["USD"]),
      Beancount.transaction(~D[2026-01-02], "*", nil, "Buy", [
        Beancount.posting("Assets:Stocks", Decimal.new("10"), "AAPL",
          cost: %{amount: Decimal.new("150"), currency: "USD"}
        ),
        Beancount.posting("Assets:Cash", Decimal.new("-1500"), "USD")
      ])
    ]

    Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
    {:ok, %Beancount.Query.Result{columns: cols}} = Beancount.Report.holdings(ledger)
    cols
    # => ["account", "units", "cost"]

# `income_statement`

```elixir
@spec income_statement(ledger()) :: result()
```

Income statement: balances of Income and Expenses accounts.

## Examples

    iex> Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
    iex> {:ok, %Beancount.Query.Result{}} = Beancount.Report.income_statement(Beancount.Report.sample_ledger())

# `journal`

```elixir
@spec journal(ledger(), String.t()) :: result()
```

Journal of postings for a single `account`, ordered by date.

## Examples

    iex> Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
    iex> {:ok, %Beancount.Query.Result{columns: cols}} =
    ...>   Beancount.Report.journal(Beancount.Report.sample_ledger(), "Assets:Bank")
    iex> "date" in cols
    true

---

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