# `Bookk.ChartOfAccounts`
[🔗](https://github.com/rwillians/bookk/blob/v1.0.0/lib/bookk/chart_of_accounts.ex#L1)

A Chart of Accounts (abbrv.: CoA) is a mapping of all the accounts
and all the ledgers that can exist in your system. But instead of
hard-coding them, you define patterns for accounts and ledgers
supported by your application using functions and pattern matching.

For example, if your application allows ledgers to have an account
for expenses related to paying salary to an employee, you could
define a function with a signature the like the one below:

    def account({:salary, {:employee, employee_id}})

And if your application, following the previous example, allows for
every employee to have their own ledger, you could define a function
with a signature like the one below:

    def ledger_id({:employee, employee_id})

## Related

- `Bookk.Notation`;
- `Bookk.AccountClass`;
- `Bookk.AccountHead`.

# `account`

```elixir
@callback account(term()) :: Bookk.AccountHead.t()
```

This function maps all possible patterns of accounts that your
application supports. It's recomended to use pattern matching and
let it crash in the event of a mismatch.

## Examples

    @impl Bookk.ChartOfAccounts
    def account(:cash), do: %Bookk.AccountHead{name: "cash", class: class("CA")}
    def account({:payables, {:user, id}}), do: %Bookk.AccountHead{name: "payables:user(#{id})", class: class("L")}

# `account_id`

```elixir
@callback account_id(ledger_id, account_head) :: String.t()
when ledger_id: String.t(), account_head: Bookk.AccountHead.t()
@callback account_id(ledger_code, account_code) :: String.t()
when ledger_code: term(), account_code: term()
```

Combines a ledger id with an account header, returning a unique id
for the account.

      id = account_id(ledger_id(:acme), account(:cash))
      #> %Bookk.AccountHead{...}

Can alternativelly be called directly with ledger code and account
code:

    id = account_id(:acme, :cash)
    #> %Bookk.AccountHead{...}

# `class`

```elixir
@callback class(id :: String.t()) :: Bookk.AccountClass.t() | nil
```

Get a `Bookk.AccountClass` definition by its id.

You are free to choose how and where you define your account classes, but you
need to provide an implementation for this function so that your classes
definitions are accessible to other modules.

## Example

    @impl Bookk.ChartOfAccounts
    def class("A"), do: %Bookk.AccountClass{id: "A", parent_id: nil, name: "Assets", natural_balance: :debit},
    def class("CA"), do: %Bookk.AccountClass{id: "CA", parent_id: "A", name: "Current Assets", natural_balance: :debit}

# `ledger_id`

```elixir
@callback ledger_id(term()) :: String.t()
```

This function maps all of your ledger codes into a ledger id string.
It's recomended to use pattern matching and let it crash in the
event of a mismatch.

## Example

    @impl Bookk.ChartOfAccounts
    def ledger_id(:acme), do: "acme"
    def ledger_id({:user, <<id::binary-size(36)>>}), do: "user(#{id})"

# `__using__`
*macro* 

By using this module, you are declaring that your module implements
the `Bookk.ChartOfAccounts` behaviour.

---

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