lib/issuing_purchase/issuing_purchase_log.ex

defmodule StarkInfra.IssuingPurchase.Log do
  alias __MODULE__, as: Log
  alias StarkInfra.Utils.Rest
  alias StarkInfra.Utils.Check
  alias StarkInfra.User.Project
  alias StarkInfra.User.Organization
  alias StarkInfra.Error

  @moduledoc """
    # IssuingPurchase.Log struct
  """

  @doc """
  Every time an IssuingPurchase entity is updated, a corresponding IssuingPurchase.Log
  is generated for the entity. This log is never generated by the
  user, but it can be retrieved to check additional information
  on the IssuingPurchase.

  ## Attributes:
    - `:id` [string]: unique id returned when the log is created. ex: "5656565656565656"
    - `:purchase` [IssuingPurchase]: IssuingPurchase entity to which the log refers to.
    - `:issuing_transaction_id` [string]: transaction ID related to the IssuingCard.
    - `:errors` [list of strings]: list of errors linked to this IssuingPurchase event
    - `:type` [string]: type of the IssuingPurchase event which triggered the log creation. ex: "approved", "canceled", "confirmed", "denied", "reversed", "voided".
    - `:created` [DateTime]: creation datetime for the log. ex: ~U[2020-03-10 10:30:0:0]
  """
  @enforce_keys [
    :id,
    :purchase,
    :issuing_transaction_id,
    :errors,
    :type,
    :created
  ]
  defstruct [
    :id,
    :purchase,
    :issuing_transaction_id,
    :errors,
    :type,
    :created
  ]

  @type t() :: %__MODULE__{}

  @doc """
  Receive a single IssuingPurchase.Log struct previously created by the Stark Infra API by its id

  ## Parameters (required):
    - `:id` [string]: struct unique id. ex: "5656565656565656"

  ## Options:
    - `:user` [Organization/Project, default nil]: Organization or Project struct returned from StarkInfra.project(). Only necessary if default project or organization has not been set in configs.

  ## Return:
    - IssuingPurchase.Log struct with updated attributes
  """
  @spec get(
    id: binary,
    user: Project.t() | Organization.t() | nil
  ) ::
    { :ok, Log.t() } |
    { :error, [Error.t()] }
  def get(id, options \\ []) do
    Rest.get_id(
      resource(),
      id,
      options
    )
  end

  @doc """
  Same as get(), but it will unwrap the error tuple and raise in case of errors.
  """
  @spec get!(
    id: binary,
    user: Project.t() | Organization.t() | nil
  ) :: any
  def get!(id, options \\ []) do
    Rest.get_id!(
      resource(),
      id,
      options
    )
  end

  @doc """
  Receive a stream of IssuingPurchase.Log structs previously created in the Stark Infra API

  ## Options:
    - `:ids` [list of strings, default nil]: list of IssuingPurchase ids to filter logs. ex: ["5656565656565656", "4545454545454545"]
    - `:limit` [integer, default nil]: maximum number of structs to be retrieved. Unlimited if nil. ex: 35
    - `:after` [Date or string, default nil]: date filter for structs created only after specified date. ex: ~D[2020-03-25]
    - `:before` [Date or string, default nil]: date filter for structs created only before specified date. ex: ~D[2020-03-25]
    - `:types` [list of strings, default nil]: filter for log event types. ex: ["approved", "canceled", "confirmed", "denied", "reversed", "voided"]
    - `:purchase_ids` [list of strings, default nil]: list of Purchase ids to filter logs. ex: ["5656565656565656", "4545454545454545"]
    - `:user` [Organization/Project, default nil]: Organization or Project struct returned from StarkInfra.project(). Only necessary if default project or organization has not been set in configs.

  ## Return:
    - stream of IssuingPurchase.Log structs with updated attributes
  """
  @spec query(
    ids: [binary],
    limit: integer,
    after: Date.t() | binary,
    before: Date.t() | binary,
    types: [binary],
    purchase_ids: [binary],
    user: Project.t() | Organization.t() | nil
  ) ::
    { :ok, {binary, [Log.t()]} } |
    { :error, [Error.t()] }
  def query(options \\ []) do
    Rest.get_list(
      resource(),
      options
    )
  end

  @doc """
  Same as query(), but it will unwrap the error tuple and raise in case of errors.
  """
  @spec query!(
    ids: [binary],
    limit: integer,
    after: Date.t() | binary,
    before: Date.t() | binary,
    types: [binary],
    purchase_ids: [binary],
    user: Project.t() | Organization.t() | nil
  ) :: any
  def query!(options \\ []) do
    Rest.get_list!(
      resource(),
      options
    )
  end

  @doc """
  Receive a list of up to 100 IssuingPurchase.Log structs previously created in the Stark Infra API and the cursor to the next page.
  Use this function instead of query if you want to manually page your requests.

  ## Options:
    - `:cursor` [string, default nil]: cursor returned on the previous page function call
    - `:ids` [list of strings, default nil]: list of IssuingPurchase ids to filter logs. ex: ["5656565656565656", "4545454545454545"]
    - `:limit` [integer, default 100]: maximum number of structs to be retrieved. Unlimited if nil. ex: 35
    - `:after` [Date or string, default nil]: date filter for structs created only after specified date. ex: ~D[2020-03-25]
    - `:before` [Date or string, default nil]: date filter for structs created only before specified date. ex: ~D[2020-03-25]
    - `:types` [list of strings, default nil]: filter for log event types. ex: ["approved", "canceled", "confirmed", "denied", "reversed", "voided"]
    - `:purchase_ids` [list of strings, default nil]: list of Purchase ids to filter logs. ex: ["5656565656565656", "4545454545454545"]
    - `:user` [Organization/Project, default nil]: Organization or Project struct returned from StarkInfra.project(). Only necessary if default project or organization has not been set in configs.

  ## Return:
    - list of IssuingPurchase.Log structs with updated attributes
    - cursor to retrieve the next page of IssuingPurchase.Log structs
  """
  @spec page(
    cursor: binary,
    ids: [binary],
    limit: integer,
    after: Date.t() | binary,
    before: Date.t() | binary,
    types: [binary],
    purchase_ids: [binary],
    user: Project.t() | Organization.t() | nil
  ) :: { :ok, {binary, [Log.t()]} } | { :error, [Error.t()] }
  def page(options \\ []) do
    Rest.get_page(
      resource(),
      options
    )
  end

  @doc """
  Same as page(), but it will unwrap the error tuple and raise in case of errors.
  """
  @spec page!(
    cursor: binary,
    ids: [binary],
    limit: integer,
    after: Date.t() | binary,
    before: Date.t() | binary,
    types: [binary],
    purchase_ids: [binary],
    user: Project.t() | Organization.t() | nil
  ) :: any
  def page!(options \\ []) do
    Rest.get_page!(
      resource(),
      options
    )
  end

  @doc false
  def resource() do
    {
      "IssuingPurchaseLog",
      &resource_maker/1
    }
  end

  @doc false
  def resource_maker(json) do
    %Log{
      id: json[:id],
      type: json[:type],
      errors: json[:errors],
      purchase: json[:purchase],
      issuing_transaction_id: json[:issuing_transaction_id],
      created: json[:created] |> Check.datetime(),
    }
  end
end