lib/services.ex

defmodule CorreiosEx.Services do
  require Logger

  import SweetXml

  @type requestParams :: %{
          contract_number: :string,
          post_card_number: :string,
          sigep_user: :string,
          sigep_password: :string
        }

  @type service :: %{
          code: :integer,
          name: :string
        }

  @headers [{"Content-Type", "application/soap+xml"}]
  @endpoint "https://apps.correios.com.br/SigepMasterJPA/AtendeClienteService/AtendeCliente"

  @spec list_services(requestParams) :: {:ok, [service]} | {:error, term()}
  def list_services(params) do
    case HTTPoison.post(@endpoint, build_body(params), @headers) do
      {:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
        parse_response(body)

      {:ok, %HTTPoison.Response{body: body}} ->
        response_error = xpath(body, ~x"//faultstring/text()"s)
        {:error, "A chamada retornou com erro: #{response_error}"}

      _ ->
        Logger.error("Unknow error to get correios services")
        {:error, "erro desconecido, por favor tente novamente mais tarde"}
    end
  end

  defp parse_response(body) do
    services_node = xpath(body, ~x"//return"l)

    {
      :ok,
      Enum.map(services_node, fn service_node ->
        %{
          code: xpath(service_node, ~x"./codigo/text()"s |> transform_by(&String.trim/1)),
          name:
          xpath(
            service_node,
            ~x"./descricao/text()"s |> transform_by(&String.trim/1)
          )
        }
      end)
    }
  end

  defp build_body(config) do
    """
    <x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cli="http://cliente.bean.master.sigep.bsb.correios.com.br/">
      <x:Header/>
      <x:Body>
        <cli:buscaServicos>
          <idContrato>#{config.contract_number}</idContrato>
          <idCartaoPostagem>#{config.post_card_number}</idCartaoPostagem>
          <usuario>#{config.sigep_user}</usuario>
          <senha>#{config.sigep_password}</senha>
        </cli:buscaServicos>
      </x:Body>
    </x:Envelope>
    """
  end
end