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

Ordem de crédito: a mensagem que move o dinheiro de um Pix.

O participante do pagador manda uma pacs.008 ao SPI, e o SPI responde com
uma `Isox.Pacs002` dizendo se liquidou ou rejeitou. Os dois lados se
amarram pelo `end_to_end_id`.

Versões 1.15 e 1.16 (ADR 0002). A struct dá nome a cada campo, em vez do
mapa genérico e cru que o motor de codec interno produz.

## O que a struct cobre

O caminho comum de um Pix: todos os campos obrigatórios da árvore real do
XSD, mais os opcionais que aparecem de fato (`InstrId`, `TxId`,
`InitgPty`, `Prxy`, `RmtInf.Ustrd`). Ficam de fora `Tax` e `RmtInf.Strd`,
ramos raros fora do fluxo padrão do Pix.

## Lote

`CdtTrfTxInf` é ilimitado no XSD, e o catálogo documenta lote de verdade
(`pacs.008_CONTA_10_msg.xml`, 10 transações numa mensagem só). `encode/3`
aceita 1 mensagem ou uma lista; `decode/1` devolve 1 struct ou uma lista,
conforme o que o XML trouxer.

Os quatro campos de `GrpHdr` (`msg_id`, `created_at`, `instr_prty`,
`svc_lvl_prtry`) valem para o XML inteiro, não por transação, então em
lote precisam estar iguais em todos os itens da lista.

## Validação

`encode/3` confere os campos obrigatórios e, depois de montar o XML, faz o
caminho de volta pelo módulo gerado. Isso reaproveita a validação de
pattern, enum e cardinalidade que o parser já faz, sem duplicar regra
nenhuma. O motor de codec sozinho não valida nada: ele confia no termo que
recebe.

# `t`

```elixir
@type t() :: %Isox.Pacs008{
  accptnc_dt_tm: DateTime.t(),
  cdtr_acct_id: String.t(),
  cdtr_acct_issr: String.t() | nil,
  cdtr_acct_proxy: String.t() | nil,
  cdtr_acct_type: String.t(),
  cdtr_agt_ispb: String.t(),
  cdtr_cpf_cnpj: String.t(),
  created_at: DateTime.t(),
  dbtr_acct_id: String.t(),
  dbtr_acct_issr: String.t() | nil,
  dbtr_acct_type: String.t(),
  dbtr_agt_ispb: String.t(),
  dbtr_cpf_cnpj: String.t(),
  dbtr_name: String.t(),
  end_to_end_id: String.t(),
  initg_pty_id: String.t() | nil,
  instr_id: String.t() | nil,
  instr_prty: String.t(),
  lcl_instrm: String.t(),
  msg_id: String.t(),
  purp_cd: String.t(),
  rmt_inf: String.t() | nil,
  svc_lvl_prtry: String.t(),
  tx_id: String.t() | nil,
  value: String.t() | number()
}
```

# `version`

```elixir
@type version() :: :v1_15 | :v1_16
```

# `decode`

```elixir
@spec decode(binary()) :: {:ok, t() | [t(), ...], version()} | {:error, term()}
```

Decodifica um XML de pacs.008 (qualquer versão) de volta para a
struct, ou para uma lista de structs quando a mensagem traz mais de uma `CdtTrfTxInf` (lote), para
uma lista de structs.

# `encode`

```elixir
@spec encode(t() | [t(), ...], Isox.AppHdr.t(), version()) ::
  {:ok, binary()} | {:error, String.t()}
```

Monta o XML (envelope completo, `AppHdr` + `Document`) para a versão
dada. Aceita 1 mensagem ou uma lista (lote: vira várias `CdtTrfTxInf`
na mesma `Document`, com `NbOfTxs` ajustado à quantidade).

`msg_id`/`created_at`/`instr_prty`/`svc_lvl_prtry` são de `GrpHdr` (uma
vez por mensagem XML). Em lote, têm que ser iguais em todos os itens
da lista.

---

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