lib/hyperswitch/payments.ex

defmodule Hyperswitch.Payments do
  import Hyperswitch.Client, only: [request: 1]

  alias Hyperswitch.Client

  ## Types

  @type payment_id :: binary()

  @type merchant_id :: binary()

  @type create_payment_params :: map()

  @type create_payment_response :: Client.response()

  @type list_payments_params :: keyword()

  @type list_payments_response :: Client.response()

  @type create_payment_session_token_body :: %{
          required(:payment_id) => binary(),
          required(:client_secret) => binary(),
          required(:wallets) => :paypal | :apple_pay | :klarna | :gpay
        }

  @type create_payment_session_token_response :: Client.response()

  @type get_payment_params :: map()

  @type get_payment_response :: Client.response()

  @type update_payment_body :: map()

  @type update_payment_response :: Client.response()

  @type cancel_payment_body :: %{required(:cancellation_reason) => binary()}

  @type cancel_payment_response :: Client.response()

  @type capture_payment_body :: %{
          required(:merchant_id) => merchant_id(),
          required(:amount_to_capture) => integer(),
          required(:refund_uncaptured_amount) => boolean(),
          required(:statement_descriptor_suffix) => binary(),
          required(:statement_descriptor_prefix) => binary()
        }

  @type capture_payment_response :: Client.response()

  @type confirm_payment_body :: map()

  @type confirm_payment_response :: Client.response()

  ## Moduele attributes

  @prefix "/payments"

  @list_params ~w[customer_id starting_after ending_before limit created created_lt created_gt created_lte created_gte]a

  ## Public functions

  @doc """
  To process a payment you will have to create a payment, attach a payment method and confirm.
  Depending on the user journey you wish to achieve, you may opt to all the steps in a single
  request or in a sequence of API request using following APIs: (i) Payments - Update,
  (ii) Payments - Confirm, and (iii) Payments - Capture.
  """
  @spec create_payment(create_payment_params()) :: create_payment_response()
  def create_payment(body) when is_map(body) do
    request(%{method: :post, path: @prefix, body: body})
  end

  @doc """
  To list the payments.
  """
  @spec list_payments(list_payments_params()) :: list_payments_response()
  def list_payments(params \\ []) when is_list(params) do
    Keyword.validate!(params, @list_params)

    request(%{method: :get, path: @prefix <> "/list", params: params})
  end

  @doc """
  To create the session object or to get session token for wallets.
  """
  @spec create_payment_session_token(create_payment_session_token_body()) :: create_payment_session_token_response()
  def create_payment_session_token(body) when is_map(body) do
    request(%{method: :post, path: @prefix <> "/session_tokens", body: body})
  end

  @doc """
  To retrieve the properties of a Payment. This may be used to get the status of a previously
  initiated payment or next action for an ongoing payment.
  """
  @spec get_payment(payment_id(), get_payment_params()) :: get_payment_response()
  def get_payment(payment_id, body) when is_binary(payment_id) and is_map(body) do
    request(%{method: :get, path: @prefix <> "/" <> payment_id, body: body})
  end

  @doc """
  To update the properties of a PaymentIntent object. This may include attaching a payment method, or attaching customer object or metadata fields after the Payment is created.
  """
  @spec update_payment(payment_id(), update_payment_body()) :: update_payment_response()
  def update_payment(payment_id, body) when is_binary(payment_id) and is_map(body) do
    request(%{method: :post, path: @prefix <> "/" <> payment_id, body: body})
  end

  @doc """
  A Payment could can be cancelled when it is in one of these statuses: `requires_payment_method`, `requires_capture`, `requires_confirmation`, `requires_customer_action`.
  """
  @spec cancel_payment(payment_id(), cancel_payment_body()) :: cancel_payment_response()
  def cancel_payment(payment_id, body) when is_binary(payment_id) and is_map(body) do
    request(%{method: :post, path: @prefix <> "/" <> payment_id <> "/cancel", body: body})
  end

  @doc """
  To capture the funds for an uncaptured payment.
  """
  @spec capture_payment(payment_id(), capture_payment_body()) :: capture_payment_response()
  def capture_payment(payment_id, body) when is_binary(payment_id) and is_map(body) do
    request(%{method: :post, path: @prefix <> "/" <> payment_id <> "/capture", body: body})
  end

  @doc """
  This API is to confirm the payment request and forward payment to the payment processor. This API provides more granular control upon when the API is forwarded to the payment processor. Alternatively you can confirm the payment within the Payments Create API.
  """
  @spec comfirm_payment(payment_id(), confirm_payment_body()) :: confirm_payment_response()
  def comfirm_payment(payment_id, body) when is_binary(payment_id) and is_map(body) do
    request(%{method: :post, path: @prefix <> "/" <> payment_id <> "/comfirm", body: body})
  end
end