defmodule CorreiosEx.Shipping do
@endpoint "http://ws.correios.com.br/calculador/CalcPrecoPrazo.asmx"
@headers [{"Content-Type", "application/soap+xml"}]
require Logger
import SweetXml
@type requestParams :: %{
code: :string,
origin: :string,
destination: :string,
weight: :positive_integer,
length: :positive_integer,
height: :positive_integer,
width: :positive_integer,
on_hand: :boolean,
declared_value: :positive_integer,
ack: :boolean
}
@type rate :: %{
error_code: :integer,
error_message: :string,
code: :integer,
eta: :string,
price: :positive_integer
}
@spec rate(requestParams) :: rate
def rate(params) do
body = build_body(params)
with {:ok, %HTTPoison.Response{body: body}} <- HTTPoison.post(@endpoint, body, @headers) do
response =
xpath(
body,
~x"//cServico",
error_code: ~x"./Erro/text()"i,
error_message: ~x"./MsgErro/text()"s,
code: ~x"./Codigo/text()"i,
price: ~x"./Valor/text()"s |> transform_by(&transform_value/1),
eta: ~x"./PrazoEntrega/text()"i |> transform_by(&calculate_delivery_date/1)
)
case response.error_code do
0 -> Map.take(response, [:code, :eta, :price])
_ -> Map.take(response, [:error_code, :error_message])
end
end
end
defp transform_value(value) do
value
|> String.replace(",", "")
|> String.to_integer()
end
defp translate_bool(true), do: "S"
defp translate_bool(_), do: "N"
defp calculate_delivery_date(qty), do: Date.add(Date.utc_today(), qty)
defp build_body(params) do
"""
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
<S:Body>
<CalcPrecoPrazo
xmlns="http://tempuri.org/">
<nCdEmpresa></nCdEmpresa>
<sDsSenha></sDsSenha>
<nCdServico>#{params.code}</nCdServico>
<sCepOrigem>#{params.origin}</sCepOrigem>
<sCepDestino>#{params.destination}</sCepDestino>
<nVlPeso>#{params.weight}</nVlPeso>
<nCdFormato>0</nCdFormato>
<nVlComprimento>#{params.length}</nVlComprimento>
<nVlAltura>#{params.height}</nVlAltura>
<nVlLargura>#{params.width}</nVlLargura>
<nVlDiametro>0</nVlDiametro>
<sCdMaoPropria>#{translate_bool(params.on_hand)}</sCdMaoPropria>
<nVlValorDeclarado>#{declared_value(params)}</nVlValorDeclarado>
<sCdAvisoRecebimento>#{translate_bool(params.ack)}</sCdAvisoRecebimento>
</CalcPrecoPrazo>
</S:Body>
</S:Envelope>
"""
end
defp declared_value(%{declare_value: true, total_items_price: total_items_price}),
do: total_items_price
defp declared_value(_), do: 0
end