lib/requests/payments/capture_payment.ex

defmodule Requests.Payments.CapturePayment do
  alias Customers.BillingAddress
  alias Customers.Phone

  @derive Jason.Encoder

  @type billing_descriptor :: %{
          name: String.t(),
          city: String.t(),
          reference: String.t()
        }

  @type customer :: %{
          id: String.t(),
          email: String.t(),
          name: String.t(),
          tax_number: String.t(),
          phone: Phone.t()
        }

  @type shipping :: %{
          address: BillingAddress.t(),
          phone: Phone.t(),
          from_address_zip: String.t()
        }

  @type t :: %__MODULE__{
          id: String.t(),
          amount: integer(),
          capture_type: String.t(),
          reference: String.t(),
          customer: customer(),
          description: String.t(),
          billing_descriptor: billing_descriptor(),
          shipping: String.t(),
          items: String.t(),
          marketplace: String.t(),
          amount_allocations: String.t(),
          processing: String.t(),
          metadata: map()
        }

  defstruct [
    :id,
    :amount,
    :capture_type,
    :reference,
    :customer,
    :description,
    :billing_descriptor,
    :shipping,
    :items,
    :marketplace,
    :amount_allocations,
    :processing,
    :metadata
  ]

  def build(%{id: id} = params) when is_binary(id) do
    %__MODULE__{
      amount: params[:amount],
      capture_type: params[:capture_type],
      reference: params[:reference],
      customer: build_customer(params[:customer]),
      description: params[:description],
      billing_descriptor: build_billing_descriptor(params[:billing_descriptor]),
      shipping: build_shipping(params[:shipping]),
      items: params[:items],
      marketplace: params[:marketplace],
      amount_allocations: params[:amount_allocations],
      processing: params[:processing],
      metadata: params[:metadata]
    }
  end

  def build(params) when is_map(params), do: {:error, "Payment must have an id"}

  def build(_), do: {:error, "params must be a map"}

  defp build_billing_descriptor(%{name: name, city: city} = params) do
    %{
      name: name,
      city: city,
      reference: params[:reference]
    }
  end

  defp build_billing_descriptor(_), do: nil

  defp build_customer(params) when is_map(params) do
    %{
      id: params[:id],
      email: params[:email],
      name: params[:name],
      tax_number: params[:tax_number],
      phone: Phone.build(params[:phone])
    }
  end

  defp build_customer(_), do: nil

  defp build_shipping(params) when is_map(params) do
    %{
      address: BillingAddress.build(params[:address]),
      phone: Phone.build(params[:address]),
      from_address_zip: params[:from_address_zip]
    }
  end

  defp build_shipping(_), do: nil
end