defmodule DaProductApp.Transactions.TransactionOperation do use Ecto.Schema import Ecto.Changeset import Ecto.Query @primary_key {:id, :id, autogenerate: true} schema "transaction_operations" do field :operation_type, :string # "refund", "cancel", "void", "reversal" field :operation_id, :string # Provider's operation ID (refundId, cancelId, etc.) field :operation_request_id, :string # Our internal request ID # Amount fields (for refunds, reversals) field :operation_amount_value, :string field :operation_amount_currency, :string field :settlement_amount_value, :string field :settlement_amount_currency, :string # Status and result fields field :status, :string # "pending", "success", "failed" field :result_code, :string field :result_status, :string field :result_message, :string field :operation_time, :utc_datetime # Settlement/Quote fields (for currency conversion operations) field :settlement_quote_currency_pair, :string field :settlement_quote_expiry_time, :utc_datetime field :settlement_quote_id, :string field :settlement_quote_price, :string field :settlement_quote_start_time, :utc_datetime # Additional metadata field :reason, :string # Reason for the operation field :metadata, :map # Any additional operation-specific data field :provider_response, :map # Full provider response for debugging belongs_to :transaction, DaProductApp.Transactions.Transaction, type: :id timestamps() end def changeset(operation, attrs) do operation |> cast(attrs, [ :transaction_id, :operation_type, :operation_id, :operation_request_id, :operation_amount_value, :operation_amount_currency, :settlement_amount_value, :settlement_amount_currency, :status, :result_code, :result_status, :result_message, :operation_time, :settlement_quote_currency_pair, :settlement_quote_expiry_time, :settlement_quote_id, :settlement_quote_price, :settlement_quote_start_time, :reason, :metadata, :provider_response ]) |> validate_required([:transaction_id, :operation_type, :status]) |> validate_inclusion(:operation_type, ["refund", "cancel", "void", "reversal"]) |> validate_inclusion(:status, ["pending", "success", "failed"]) end # Helper functions for specific operation types def create_refund_operation(transaction_id, attrs) do attrs |> Map.put(:transaction_id, transaction_id) |> Map.put(:operation_type, "refund") |> create_operation() end def create_cancel_operation(transaction_id, attrs) do attrs |> Map.put(:transaction_id, transaction_id) |> Map.put(:operation_type, "cancel") |> create_operation() end def create_void_operation(transaction_id, attrs) do attrs |> Map.put(:transaction_id, transaction_id) |> Map.put(:operation_type, "void") |> create_operation() end def create_reversal_operation(transaction_id, attrs) do attrs |> Map.put(:transaction_id, transaction_id) |> Map.put(:operation_type, "reversal") |> create_operation() end defp create_operation(attrs) do %__MODULE__{} |> changeset(attrs) |> DaProductApp.Repo.insert() end # Query helpers def get_operations_by_transaction(transaction_id) do from(op in __MODULE__, where: op.transaction_id == ^transaction_id) |> DaProductApp.Repo.all() end def get_operations_by_type(transaction_id, operation_type) do from(op in __MODULE__, where: op.transaction_id == ^transaction_id and op.operation_type == ^operation_type) |> DaProductApp.Repo.all() end def get_successful_refunds(transaction_id) do from(op in __MODULE__, where: op.transaction_id == ^transaction_id and op.operation_type == "refund" and op.status == "success") |> DaProductApp.Repo.all() end end