defmodule ApiBrasil.Consulta do @moduledoc """ Monta o body das consultas por crédito (`POST /consulta/{servico}/credits`). O campo `tipo` define o produto consultado — os tipos conhecidos estão em `ApiBrasil.Generated.Catalog.consulta_tipos/0`. alias ApiBrasil.{Consulta, Data} "lista-socios" |> Consulta.new() |> Consulta.field("cnpj", "00000000000000") |> then(&Data.Consulta.cnpj(client, &1)) # modo homologação (sandbox, sem cobrança) "serasa-score-pj" |> Consulta.new() |> Consulta.homolog(true) |> Consulta.field("cnpj", "00000000000000") Qualquer função de serviço aceita a struct diretamente no lugar do mapa. """ @type t :: %__MODULE__{ tipo: String.t() | nil, homolog: boolean(), lite: boolean(), agrupados: [String.t()], extra: [String.t()], fields: map() } @doc """ Body de uma consulta por crédito. - `:tipo` — tipo/serviço da consulta (ex: `"lista-socios"`, `"serasa-score-pf"`); - `:homolog` — modo homologação (sandbox, sem cobrança), quando suportado; - `:lite` — versão reduzida da consulta, quando suportada; - `:agrupados` — consultas agrupadas; - `:extra` — serviços extras; - `:fields` — campos específicos do produto (ex: `%{"cnpj" => "..."}`). """ defstruct tipo: nil, homolog: false, lite: false, agrupados: [], extra: [], fields: %{} @doc "Cria uma consulta do `tipo` informado." @spec new(String.t() | nil, keyword()) :: t() def new(tipo \\ nil, fields \\ []) do struct!(%__MODULE__{tipo: tipo}, fields) end @doc "Ativa/desativa o modo homologação." @spec homolog(t(), boolean()) :: t() def homolog(%__MODULE__{} = consulta, homolog \\ true), do: %{consulta | homolog: homolog} @doc "Ativa/desativa a versão reduzida da consulta." @spec lite(t(), boolean()) :: t() def lite(%__MODULE__{} = consulta, lite \\ true), do: %{consulta | lite: lite} @doc "Define as consultas agrupadas." @spec agrupados(t(), [String.t()]) :: t() def agrupados(%__MODULE__{} = consulta, agrupados) when is_list(agrupados) do %{consulta | agrupados: Enum.map(agrupados, &to_string/1)} end @doc "Define os serviços extras." @spec extra(t(), [String.t()]) :: t() def extra(%__MODULE__{} = consulta, extra) when is_list(extra) do %{consulta | extra: Enum.map(extra, &to_string/1)} end @doc "Adiciona um campo do produto." @spec field(t(), String.t() | atom(), term()) :: t() def field(%__MODULE__{} = consulta, key, value) do %{consulta | fields: Map.put(consulta.fields, to_string(key), value)} end @doc "Mescla um mapa/keyword nos campos do produto." @spec fields(t(), map() | keyword()) :: t() def fields(%__MODULE__{} = consulta, fields) when is_map(fields) or is_list(fields) do extra = Map.new(fields, fn {key, value} -> {to_string(key), value} end) %{consulta | fields: Map.merge(consulta.fields, extra)} end @doc "Monta o body da consulta." @spec to_map(t()) :: map() def to_map(%__MODULE__{} = consulta) do %{} |> put_unless_nil("tipo", consulta.tipo) |> put_when(consulta.homolog, "homolog", true) |> put_when(consulta.lite, "lite", true) |> put_when(consulta.agrupados != [], "agrupados", consulta.agrupados) |> put_when(consulta.extra != [], "extra", consulta.extra) |> Map.merge(consulta.fields) end defp put_unless_nil(map, _key, nil), do: map defp put_unless_nil(map, key, value), do: Map.put(map, key, value) defp put_when(map, false, _key, _value), do: map defp put_when(map, true, key, value), do: Map.put(map, key, value) end