# `Nfse.DPS`
[🔗](https://github.com/ideia4it/nfse/blob/v0.1.0/lib/nfse/dps.ex#L1)

A DPS (Declaração de Prestação de Serviço) que vira NFS-e, montada a partir dos campos que quem
emite preenche.

Os campos do struct são os elementos do `Nfse.Schema.V1_01.TCInfDPS`, com os mesmos nomes e as
mesmas regras de conversão: cada grupo aninhado aceita o struct gerado ou um mapa com as mesmas
chaves. `build/2` aceita o struct ou um mapa com essas chaves.

## O que `build/2` calcula

  * `Id` do `infDPS`, com 45 caracteres: `"DPS"`, `c_loc_emi`, o tipo da inscrição federal
    (`"1"` para CPF, `"2"` para CNPJ), o CNPJ ou CPF com 14 dígitos, a `serie` com 5 e o `n_dps`
    com 15, completados com zeros à esquerda só dentro do `Id`. A inscrição é a de quem emite,
    conforme `tp_emit`: `"1"` o prestador (`prest`), `"2"` o tomador (`toma`) e `"3"` o
    intermediário (`interm`)
  * `versao` da raiz, sempre `"1.01"`
  * `tp_amb`, a partir do ambiente do cliente. Pode ser omitido; se vier, precisa ser o do
    cliente, para que um documento de produção nunca vá à produção restrita, nem o contrário

Depois valida, assina o `infDPS` com o certificado do cliente e devolve o XML canônico, pronto
para enviar, com o `Id`, que serve para conferir a DPS na Sefin. Nada é reescrito entre assinar e
devolver.

## Erros

Os erros voltam juntos, como `%Nfse.Error{kind: :validation}`, antes de qualquer assinatura. Além
dos erros do schema, descritos em `Nfse.Schema.Runtime`:

| Caminho | Erro | Quando |
|---|---|---|
| `id` | `:unknown_field` | o chamador passou `id`, que é sempre calculado |
| `tp_amb` | `:environment` | `tp_amb` diferente do ambiente do cliente |
| `prest`, `toma` ou `interm` | `:required` | o grupo de quem emite, conforme `tp_emit`, está ausente |
| `prest`, `toma` ou `interm` | `:inscription` | quem emite não tem CNPJ nem CPF (usa `nif` ou `c_nao_nif`) |

## Exemplo

    Nfse.DPS.build(
      %Nfse.DPS{
        dh_emi: ~U[2026-11-03 13:00:00Z],
        ver_aplic: "nfse-0.1.0",
        serie: "1",
        n_dps: 42,
        d_compet: ~D[2026-11-03],
        tp_emit: 1,
        c_loc_emi: "2927408",
        prest: %{
          cnpj: "11222333000181",
          reg_trib: %{op_simp_nac: 3, reg_ap_trib_sn: 1, reg_esp_trib: 0}
        },
        toma: %{cpf: "52998224725", x_nome: "Ana Souza"},
        serv: %{
          loc_prest: %{c_loc_prestacao: "2927408"},
          c_serv: %{c_trib_nac: "060101", x_desc_serv: "Corte de cabelo"}
        },
        valores: %{
          v_serv_prest: %{v_serv: Decimal.new("49.90")},
          trib: %{
            trib_mun: %{trib_issqn: 1, tp_ret_issqn: 1},
            tot_trib: %{p_tot_trib_sn: Decimal.new("6.00")}
          }
        }
      },
      client
    )
    #=> {:ok, %{xml: "<DPS xmlns=...", id: "DPS292740821122233300018100001000000000000042"}}

# `built`

```elixir
@type built() :: %{xml: binary(), id: String.t()}
```

# `t`

```elixir
@type t() :: %Nfse.DPS{
  c_loc_emi: term(),
  c_motivo_emis_ti: term(),
  ch_nfse_rej: term(),
  d_compet: term(),
  dh_emi: term(),
  ibscbs: term(),
  interm: term(),
  n_dps: term(),
  prest: term(),
  serie: term(),
  serv: term(),
  subst: term(),
  toma: term(),
  tp_amb: term(),
  tp_emit: term(),
  valores: term(),
  ver_aplic: term()
}
```

# `build`

```elixir
@spec build(t() | map(), Nfse.Client.t()) :: {:ok, built()} | {:error, Nfse.Error.t()}
```

Calcula `Id`, `versao` e `tpAmb`, valida, assina e devolve o XML da DPS com o `Id`.

---

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