cover/Elixir.WalletIntegrations.Commands.InitiatePayment.html

1 defmodule WalletIntegrations.Commands.InitiatePayment do
2 @moduledoc """
3 Create an outbound payment request and enqueue it for async dispatch to the provider.
4
5 Steps:
6 1. Build PaymentRequest domain struct.
7 2. Store in PaymentRequestStore.
8 3. Enqueue PaymentWorker job on :integrations_payment queue.
9 4. Emit PaymentInitiated domain event.
10 5. Emit audit event.
11
12 Returns `{:ok, PaymentRequest.t()}` or `{:error, reason}`.
13 """
14
15 alias WalletIntegrations.{PaymentRequest, PaymentRequestStore, JobQueue}
16 alias WalletIntegrations.Workers.PaymentWorker
17 alias WalletIntegrations.Events.PaymentInitiated
18 alias WalletObservability.AuditEvent
19
20 @spec execute(
21 transfer_id :: String.t(),
22 provider :: atom(),
23 amount :: pos_integer(),
24 currency :: String.t(),
25 opts :: keyword()
26 ) :: {:ok, PaymentRequest.t()} | {:error, term()}
27 41 def execute(transfer_id, provider, amount, currency, opts \\ []) do
28 21 correlation_id =
29 Keyword.get(opts, :correlation_id, WalletSharedKernel.Correlation.new_correlation_id())
30
31 21 request =
32 PaymentRequest.new(transfer_id, provider, amount, currency,
33 idempotency_key: Keyword.get(opts, :idempotency_key),
34 correlation_id: correlation_id,
35 metadata: Keyword.get(opts, :metadata, %{})
36 )
37
38 21 with :ok <- PaymentRequestStore.store(request),
39 21 {:ok, _job_id} <-
40 JobQueue.enqueue(:integrations_payment, PaymentWorker, %{
41 21 "request_id" => request.request_id,
42 "operation" => "initiate",
43 "correlation_id" => correlation_id
44 }) do
45 21 emit_event(
46 21 PaymentInitiated.build(request.request_id,
47 transfer_id: transfer_id,
48 provider: provider,
49 amount: amount,
50 currency: currency,
51 correlation_id: correlation_id
52 )
53 )
54
55 21 emit_audit(request.request_id, correlation_id, :success, %{provider: provider, amount: amount})
56 {:ok, request}
57 end
58 rescue
59
:-(
error -> {:error, error}
60 end
61
62 21 defp emit_event(event) do
63 21 pubsub = Application.get_env(:wallet_integrations, :pubsub, WalletWeb.PubSub)
64 21 apply(Phoenix.PubSub, :broadcast, [pubsub, "wallet_integrations:events", {:domain_event, event}])
65 rescue
66
:-(
_ -> :ok
67 end
68
69 21 defp emit_audit(request_id, correlation_id, outcome, metadata) do
70 21 audit =
71 AuditEvent.build(:integrations, "payment_initiated", "payment_request", request_id,
72 outcome,
73 correlation_id: correlation_id,
74 metadata: metadata
75 )
76
77 21 :telemetry.execute([:wallet_integrations, :audit], %{}, audit)
78 rescue
79
:-(
_ -> :ok
80 end
81 end
Line Hits Source