defmodule DaProductApp.Disputes do @moduledoc """ The Disputes context. """ import Ecto.Query, warn: false alias DaProductApp.Repo alias DaProductApp.Disputes.Dispute @doc """ Returns the list of disputes with optional filters and pagination. """ def list_disputes(params \\ %{}) do Dispute |> filter_by_status(params) |> filter_by_date_range(params) |> filter_by_search(params) |> order_by([d], desc: d.inserted_at) |> paginate(params) |> Repo.all() end @doc """ Returns the total count of disputes matching the filters. """ def count_disputes(params \\ %{}) do Dispute |> filter_by_status(params) |> filter_by_date_range(params) |> filter_by_search(params) |> Repo.aggregate(:count, :id) end @doc """ Gets a single dispute by dispute_id. """ def get_dispute_by_dispute_id(dispute_id) do Repo.get_by(Dispute, dispute_id: dispute_id) end @doc """ Gets a single dispute by id. """ def get_dispute!(id), do: Repo.get!(Dispute, id) @doc """ Creates a dispute. """ def create_dispute(attrs \\ %{}) do attrs_with_id = Map.put_new(attrs, "dispute_id", Dispute.generate_dispute_id()) %Dispute{} |> Dispute.changeset(attrs_with_id) |> Repo.insert() end @doc """ Updates a dispute. """ def update_dispute(%Dispute{} = dispute, attrs) do dispute |> Dispute.changeset(attrs) |> Repo.update() end @doc """ Deletes a dispute. """ def delete_dispute(%Dispute{} = dispute) do Repo.delete(dispute) end @doc """ Returns an `%Ecto.Changeset{}` for tracking dispute changes. """ def change_dispute(%Dispute{} = dispute, attrs \\ %{}) do Dispute.changeset(dispute, attrs) end # Private helper functions defp filter_by_status(query, %{"status" => status}) when not is_nil(status) do query |> where([d], d.status == ^status) end defp filter_by_status(query, _), do: query defp filter_by_date_range(query, %{"from_date" => from_date, "to_date" => to_date}) when not is_nil(from_date) and not is_nil(to_date) do with {:ok, from_date_parsed} <- Date.from_iso8601(from_date), {:ok, to_date_parsed} <- Date.from_iso8601(to_date) do from_datetime = DateTime.new!(from_date_parsed, ~T[00:00:00]) to_datetime = DateTime.new!(to_date_parsed, ~T[23:59:59]) query |> where([d], d.inserted_at >= ^from_datetime and d.inserted_at <= ^to_datetime) else _ -> query end end defp filter_by_date_range(query, %{"from_date" => from_date}) when not is_nil(from_date) do with {:ok, from_date_parsed} <- Date.from_iso8601(from_date) do from_datetime = DateTime.new!(from_date_parsed, ~T[00:00:00]) query |> where([d], d.inserted_at >= ^from_datetime) else _ -> query end end defp filter_by_date_range(query, %{"to_date" => to_date}) when not is_nil(to_date) do with {:ok, to_date_parsed} <- Date.from_iso8601(to_date) do to_datetime = DateTime.new!(to_date_parsed, ~T[23:59:59]) query |> where([d], d.inserted_at <= ^to_datetime) else _ -> query end end defp filter_by_date_range(query, _), do: query defp filter_by_search(query, %{"search" => search}) when not is_nil(search) do search_term = "%#{search}%" query |> where([d], ilike(d.dispute_id, ^search_term) or ilike(d.txn_id, ^search_term)) end defp filter_by_search(query, _), do: query defp paginate(query, %{"page" => page_str, "page_size" => page_size_str}) do page = case Integer.parse(page_str) do {n, ""} when n > 0 -> n _ -> 1 end page_size = case Integer.parse(page_size_str) do {n, ""} when n > 0 -> n _ -> 10 end offset = (page - 1) * page_size query |> limit(^page_size) |> offset(^offset) end defp paginate(query, %{"page" => page}) do paginate(query, %{"page" => page, "page_size" => "10"}) end defp paginate(query, _), do: query end