cover/Elixir.WalletIntegrations.ProviderAdapter.html

1 defmodule WalletIntegrations.ProviderAdapter do
2 @moduledoc """
3 Port behaviour for external payment provider adapters (ADR 0008).
4
5 Every provider integration must implement this behaviour.
6 Domain apps call this contract only; they never call provider SDKs or APIs directly.
7
8 ## Contract rules
9 - All operations return `{:ok, AdapterResult.t()}` on success.
10 - All operations return `{:error, AdapterResult.t()}` on failure.
11 - Adapter implementations must handle timeouts and return `AdapterResult` with
12 `status: :unknown` and `retryable: true` for unresolved outcomes.
13 - Provider-specific fields must be isolated in `AdapterResult.metadata`.
14
15 ## Supported operations
16 - `initiate_payment/1` — submit a new payment request to the provider.
17 - `get_payment_status/1` — query current payment status by provider reference.
18 - `cancel_payment/1` — cancel a pending payment (when supported).
19 - `refund_payment/2` — initiate a refund for a completed payment (when supported).
20 """
21
22 alias WalletIntegrations.{AdapterRequest, AdapterResult}
23
24 @doc """
25 Submit a new payment request to the provider.
26 Returns `{:ok, result}` with `status: :accepted | :pending` when the provider has received
27 the request. Returns `{:error, result}` on failure.
28 """
29 @callback initiate_payment(request :: AdapterRequest.t()) ::
30 {:ok, AdapterResult.t()} | {:error, AdapterResult.t()}
31
32 @doc """
33 Query the current state of a payment by provider reference.
34 Returns `{:ok, result}` with normalized status, or `{:error, result}` on failure.
35 """
36 @callback get_payment_status(provider_ref :: String.t()) ::
37 {:ok, AdapterResult.t()} | {:error, AdapterResult.t()}
38
39 @doc """
40 Cancel a pending payment. Not all providers support this operation.
41 Returns `{:ok, result}` when cancellation is accepted, or `{:error, result}` when
42 unsupported or already terminal.
43 """
44 @callback cancel_payment(provider_ref :: String.t()) ::
45 {:ok, AdapterResult.t()} | {:error, AdapterResult.t()}
46
47 @doc """
48 Initiate a refund for a completed payment. Not all providers support this operation.
49 `amount` is in minor currency units.
50 Returns `{:ok, result}` when refund is accepted, or `{:error, result}` on failure.
51 """
52 @callback refund_payment(provider_ref :: String.t(), amount :: pos_integer()) ::
53 {:ok, AdapterResult.t()} | {:error, AdapterResult.t()}
54
55 @doc """
56 Resolve the adapter module for a given provider atom.
57 Falls back to StubAdapter if not configured.
58 """
59 @spec for_provider(provider :: atom()) :: module()
60 def for_provider(provider) do
61 3 configured =
62 Application.get_env(:wallet_integrations, :adapters, %{})
63 |> Map.get(provider)
64
65 3 configured ||
66 2 Application.get_env(:wallet_integrations, :payment_adapter, WalletIntegrations.Adapters.StubAdapter)
67 end
68 end
Line Hits Source