cover/Elixir.WalletLimitsFees.FeePolicy.html

1 defmodule WalletLimitsFees.FeePolicy do
2 @moduledoc """
3 Struct representing a fee policy for a given tier, currency, and transfer type.
4
5 Supports flat fee, percentage fee (as a float), min, and max fee ceilings.
6 Versioned to support audit traceability per ADR 0011.
7 """
8
9 alias WalletSharedKernel.TypedId
10
11 @valid_transfer_types [:internal, :p2p, :external]
12
13 @enforce_keys [
14 :policy_id, :tier, :currency, :transfer_type,
15 :flat_fee, :percentage_fee, :min_fee, :max_fee,
16 :version, :active, :created_at, :updated_at
17 ]
18
:-(
defstruct [
19 :policy_id, :tier, :currency, :transfer_type, :created_at, :updated_at,
20 flat_fee: 0,
21 percentage_fee: 0.0,
22 min_fee: 0,
23 max_fee: 0,
24 version: 1,
25 active: true
26 ]
27
28 @type t :: %__MODULE__{
29 policy_id: String.t(),
30 tier: atom(),
31 currency: String.t(),
32 transfer_type: :internal | :p2p | :external,
33 flat_fee: non_neg_integer(),
34 percentage_fee: float(),
35 min_fee: non_neg_integer(),
36 max_fee: non_neg_integer(),
37 version: pos_integer(),
38 active: boolean(),
39 created_at: DateTime.t(),
40 updated_at: DateTime.t()
41 }
42
43 @doc "Creates a new fee policy."
44 @spec new(tier :: atom(), currency :: String.t(), transfer_type :: atom(), attrs :: map()) :: t()
45
:-(
def new(tier, currency, transfer_type, attrs \\ %{}) do
46 14 now = DateTime.utc_now()
47 14 %__MODULE__{
48 policy_id: TypedId.generate("fp"),
49 tier: tier,
50 currency: currency,
51 transfer_type: transfer_type,
52 flat_fee: Map.get(attrs, :flat_fee, 0),
53 percentage_fee: Map.get(attrs, :percentage_fee, 0.0),
54 min_fee: Map.get(attrs, :min_fee, 0),
55 max_fee: Map.get(attrs, :max_fee, 0),
56 version: 1,
57 active: true,
58 created_at: now,
59 updated_at: now
60 }
61 end
62
63 @doc "Bumps version and applies new attribute values from a map."
64 @spec bump_version(t(), attrs :: map()) :: t()
65 def bump_version(%__MODULE__{} = policy, attrs) do
66 1 %{policy |
67 1 version: policy.version + 1,
68 updated_at: DateTime.utc_now(),
69 1 flat_fee: Map.get(attrs, :flat_fee, policy.flat_fee),
70 1 percentage_fee: Map.get(attrs, :percentage_fee, policy.percentage_fee),
71 1 min_fee: Map.get(attrs, :min_fee, policy.min_fee),
72 1 max_fee: Map.get(attrs, :max_fee, policy.max_fee)
73 }
74 end
75
76 @doc "Returns the list of valid transfer types."
77
:-(
def valid_transfer_types, do: @valid_transfer_types
78 end
Line Hits Source