# `Isox.Dictionary`
[🔗](https://github.com/RicardoSantos-99/isox/blob/v0.2.0/lib/isox/dictionary.ex#L1)

O que cada campo de cada mensagem quer dizer.

Quem integra com o SPI passa boa parte do tempo com a planilha do catálogo
aberta do lado do editor, só para descobrir que `dbtr_acct_id` é a conta do
pagador e que `purp_cd` só aceita cinco valores. Este módulo traz essa
informação para dentro do código.

    iex> {:ok, entrada} = Isox.Dictionary.field(Isox.Pacs008, :dbtr_acct_id)
    iex> entrada.name_br
    "contaUsuarioPagador"

A mesma informação aparece de três formas, todas vindas da mesma fonte:

- como dado, em `fields/1` e `field/2`, para quem quer montar tela, validar
  ou gerar formulário;
- como texto para ler no IEx, em `explain/2`;
- como tabela na documentação de cada mensagem, montada em tempo de
  compilação por `doc/1`. A tabela que você vê em `Isox.Pacs008` é esta
  aqui, renderizada.

Isso é de propósito: descrição que mora em dois lugares diverge, e a que
diverge é sempre a que alguém vai ler.

## De onde vêm as descrições

Dos documentos que o Banco Central publica para o SPI: o XSD de cada
mensagem, a planilha do catálogo (que traz o nome brasileiro, a
obrigatoriedade, o tamanho e a tabela de domínios de cada campo) e os
manuais do Pix.

O texto das descrições é escrito aqui, não copiado de lá. O catálogo é a
fonte normativa e continua sendo: em caso de divergência, quem manda é o
documento oficial, e é para lá que `name_br` serve de chave de busca.

## O que não está aqui

Só os campos que as structs do isox expõem. As structs cobrem o caminho
comum de cada mensagem, não a árvore inteira do XSD, então ramos raros que
a lib não modela também não aparecem no dicionário. `Isox.Pacs008`, por
exemplo, não modela `Tax` nem `RmtInf.Strd`.

# `codes`

```elixir
@spec codes(module(), atom()) :: {:ok, %{optional(String.t()) =&gt; String.t()}} | :error
```

Os valores aceitos por um campo de domínio, com o significado de cada um.

    iex> {:ok, codigos} = Isox.Dictionary.codes(Isox.Pacs008, :purp_cd)
    iex> codigos["GSCB"]
    "Pix Troco: compra com saque de dinheiro em espécie no mesmo pagamento."

Devolve `:error` para campo que não é de domínio (texto livre, valor, data)
e para campo que não existe.

As tabelas de rejeição estão aqui, incluindo a do `pacs.002`, que é a mais
consultada de quem integra com o SPI. São também as que mais mudam de uma
versão do catálogo para outra: confira contra a versão que você está
usando antes de tratar qualquer código como definitivo.

# `doc`

```elixir
@spec doc(module()) :: String.t()
```

O bloco de documentação de uma mensagem, em Markdown.

Chamado em tempo de compilação pelo `@moduledoc` de cada mensagem, para a
tabela de campos ser a mesma coisa que a API devolve.

# `explain`

```elixir
@spec explain(module(), atom()) :: String.t()
```

O campo explicado em texto corrido, para ler no IEx.

    Isox.Pacs008 |> Isox.Dictionary.explain(:dbtr_acct_id) |> IO.puts()

# `field`

```elixir
@spec field(module(), atom()) :: {:ok, Isox.Dictionary.Entry.t()} | :error
```

Um campo específico.

    iex> {:ok, entrada} = Isox.Dictionary.field(Isox.Pacs008, :purp_cd)
    iex> entrada.name_br
    "finalidadeDaTransacao"

    iex> Isox.Dictionary.field(Isox.Pacs008, :nao_existe)
    :error

# `fields`

```elixir
@spec fields(module()) :: [Isox.Dictionary.Entry.t()]
```

Todos os campos de uma mensagem, na ordem em que aparecem no XML.

    iex> Isox.Dictionary.fields(Isox.Pibr001) |> Enum.map(& &1.field)
    [:msg_id, :created_at, :data]

# `messages`

```elixir
@spec messages() :: [module()]
```

Mensagens que o dicionário cobre.

# `search`

```elixir
@spec search(String.t()) :: [{module(), Isox.Dictionary.Entry.t()}]
```

Procura um termo em todos os campos de todas as mensagens.

Busca no nome do campo na struct, no nome brasileiro, no caminho XML e na
descrição. Ignora acento e caixa, porque ninguém lembra se o catálogo
escreveu "transacao" ou "transação".

    iex> Isox.Dictionary.search("idFimAFim") |> Enum.any?(fn {m, e} ->
    ...>   m == Isox.Pacs008 and e.field == :end_to_end_id
    ...> end)
    true

---

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