cover/Elixir.WalletLimitsFees.Commands.UpsertLimitPolicy.html

1 defmodule WalletLimitsFees.Commands.UpsertLimitPolicy do
2 @moduledoc """
3 Command handler for creating or updating a limit policy.
4
5 If a policy already exists for the given tier/currency pair, it is versioned
6 and updated. Otherwise a new policy is created.
7 """
8
9 alias WalletLimitsFees.{LimitPolicy, PolicyStore}
10 alias WalletLimitsFees.Events.LimitPolicyUpdated
11 alias WalletObservability.AuditEvent
12
13 @doc """
14 Executes the upsert limit policy command.
15
16 Params map keys:
17 - `:tier` — `:standard | :premium | :business`
18 - `:currency` — ISO 4217 currency code string
19 - `:max_transaction_amount` — maximum single transaction amount (minor units)
20 - `:daily_limit` — maximum daily spend (minor units)
21 - `:monthly_limit` — maximum monthly spend (minor units)
22 - `:correlation_id` — optional correlation ID
23
24 Returns `{:ok, policy}` or `{:error, reason}`.
25 """
26 @spec execute(params :: map()) :: {:ok, LimitPolicy.t()} | {:error, term()}
27 7 def execute(params) do
28 7 tier = Map.fetch!(params, :tier)
29 7 currency = Map.fetch!(params, :currency)
30 7 correlation_id =
31 Map.get(params, :correlation_id, WalletSharedKernel.Correlation.new_correlation_id())
32
33 7 policy =
34 case PolicyStore.get_limit_policy(tier, currency) do
35 {:error, :not_found} ->
36 6 LimitPolicy.new(
37 tier,
38 currency,
39 Map.fetch!(params, :max_transaction_amount),
40 Map.fetch!(params, :daily_limit),
41 Map.fetch!(params, :monthly_limit)
42 )
43
44 {:ok, existing} ->
45 1 LimitPolicy.bump_version(existing, params)
46 end
47
48 7 :ok = PolicyStore.store_limit_policy(policy)
49
50 7 emit_event(
51 7 LimitPolicyUpdated.build(policy.policy_id, tier, currency,
52 correlation_id: correlation_id,
53 7 version: policy.version
54 )
55 )
56
57 7 audit =
58 7 AuditEvent.build(:policy, "limit_policy_upserted", "policy", policy.policy_id, :success,
59 correlation_id: correlation_id,
60 7 metadata: %{tier: tier, currency: currency, version: policy.version}
61 )
62
63 7 :telemetry.execute([:wallet_limits_fees, :audit], %{}, audit)
64
65 {:ok, policy}
66 rescue
67
:-(
error -> {:error, error}
68 end
69
70 7 defp emit_event(event) do
71 7 pubsub = Application.get_env(:wallet_limits_fees, :pubsub, WalletWeb.PubSub)
72 7 apply(Phoenix.PubSub, :broadcast, [pubsub, "wallet_limits_fees:events", {:domain_event, event}])
73 rescue
74
:-(
_ -> :ok
75 end
76 end
Line Hits Source