cover/Elixir.WalletLimitsFees.Commands.UpsertFeePolicy.html

1 defmodule WalletLimitsFees.Commands.UpsertFeePolicy do
2 @moduledoc """
3 Command handler for creating or updating a fee policy.
4
5 If a policy already exists for the given tier/currency/transfer_type combination,
6 it is versioned and updated. Otherwise a new policy is created.
7 """
8
9 alias WalletLimitsFees.{FeePolicy, PolicyStore}
10 alias WalletLimitsFees.Events.FeePolicyUpdated
11 alias WalletObservability.AuditEvent
12
13 @doc """
14 Executes the upsert fee policy command.
15
16 Params map keys:
17 - `:tier` — `:standard | :premium | :business`
18 - `:currency` — ISO 4217 currency code string
19 - `:transfer_type` — `:internal | :p2p | :external`
20 - `:flat_fee` — flat fee in minor units (default 0)
21 - `:percentage_fee` — fraction e.g. 0.015 = 1.5% (default 0.0)
22 - `:min_fee` — minimum fee floor in minor units (default 0)
23 - `:max_fee` — maximum fee ceiling; 0 means no ceiling (default 0)
24 - `:correlation_id` — optional correlation ID
25
26 Returns `{:ok, policy}` or `{:error, reason}`.
27 """
28 @spec execute(params :: map()) :: {:ok, FeePolicy.t()} | {:error, term()}
29 7 def execute(params) do
30 7 tier = Map.fetch!(params, :tier)
31 7 currency = Map.fetch!(params, :currency)
32 7 transfer_type = Map.fetch!(params, :transfer_type)
33 7 correlation_id =
34 Map.get(params, :correlation_id, WalletSharedKernel.Correlation.new_correlation_id())
35
36 7 policy =
37 case PolicyStore.get_fee_policy(tier, currency, transfer_type) do
38 {:error, :not_found} ->
39 6 FeePolicy.new(tier, currency, transfer_type, params)
40
41 {:ok, existing} ->
42 1 FeePolicy.bump_version(existing, params)
43 end
44
45 7 :ok = PolicyStore.store_fee_policy(policy)
46
47 7 emit_event(
48 7 FeePolicyUpdated.build(policy.policy_id, tier, currency, transfer_type,
49 correlation_id: correlation_id,
50 7 version: policy.version
51 )
52 )
53
54 7 audit =
55 7 AuditEvent.build(:policy, "fee_policy_upserted", "policy", policy.policy_id, :success,
56 correlation_id: correlation_id,
57 7 metadata: %{tier: tier, currency: currency, transfer_type: transfer_type, version: policy.version}
58 )
59
60 7 :telemetry.execute([:wallet_limits_fees, :audit], %{}, audit)
61
62 {:ok, policy}
63 rescue
64
:-(
error -> {:error, error}
65 end
66
67 7 defp emit_event(event) do
68 7 pubsub = Application.get_env(:wallet_limits_fees, :pubsub, WalletWeb.PubSub)
69 7 apply(Phoenix.PubSub, :broadcast, [pubsub, "wallet_limits_fees:events", {:domain_event, event}])
70 rescue
71
:-(
_ -> :ok
72 end
73 end
Line Hits Source