defmodule Plaid.Signal do
@moduledoc """
Functions for Plaid `signal` endpoint.
"""
alias Plaid.Client.Request
alias Plaid.Client
@derive Jason.Encoder
defstruct scores: nil,
core_attributes: nil,
ruleset: nil,
warnings: [],
request_id: nil
@type t :: %__MODULE__{
scores: Plaid.Signal.Scores.t(),
core_attributes: map(),
ruleset: Plaid.Signal.Ruleset.t(),
warnings: [Plaid.Signal.Warning.t()],
request_id: String.t()
}
@type params :: %{required(atom) => term}
@type config :: %{required(atom) => String.t() | keyword}
@type error :: {:error, Plaid.Error.t() | any()} | no_return
defmodule Scores do
@moduledoc """
Plaid Signal Scores data structure
"""
@derive Jason.Encoder
defstruct customer_initiated_return_risk: nil,
bank_initiated_return_risk: nil
@type t :: %__MODULE__{
customer_initiated_return_risk: Plaid.Signal.Scores.Risk.t(),
bank_initiated_return_risk: Plaid.Signal.Scores.Risk.t()
}
defmodule Risk do
@moduledoc """
Plaid Signal Scores Risk data structure.
"""
@derive Jason.Encoder
defstruct score: nil, risk_tier: nil
@type t :: %__MODULE__{score: integer(), risk_tier: integer()}
end
end
defmodule Ruleset do
@moduledoc """
Plaid Signal Ruleset data structure
"""
@derive Jason.Encoder
defstruct ruleset_key: nil,
outcome: nil
@type t :: %__MODULE__{
ruleset_key: String.t(),
outcome: String.t()
}
end
defmodule Warning do
@moduledoc """
Plaid Signal Warning data structure
"""
@derive Jason.Encoder
defstruct warning_type: nil,
warning_code: nil,
warning_message: nil
@type t :: %__MODULE__{
warning_type: String.t(),
warning_code: String.t(),
warning_message: String.t()
}
end
@doc """
Evaluate a planned ACH transaction.
Parameters
```
%{
access_token: "access-sandbox-71e02f71-0960-4a27-abd2-5631e04f2175",
account_id: "3gE5gnRzNyfXpBK5wEEKcymJ5albGVUqg77gr",
client_transaction_id: "txn12345",
amount: 123.45,
client_user_id: "user1234",
user: %{
name: %{
prefix: "Ms.",
given_name: "Jane",
middle_name: "Leah",
family_name: "Doe",
suffix: "Jr.",
},
phone_number: "+14152223333",
email_address: "jane.doe@example.com",
address: %{
street: "2493 Leisure Lane",
city: "San Matias",
region: "CA",
postal_code: "93405-2255",
country: "US",
},
},
device: %{
ip_address: "198.30.2.2",
user_agent: "Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X)",
},
user_present: true,
is_recurring: false
}
```
"""
@spec evaluate(params, config) :: {:ok, Plaid.Signal.t()} | error
def evaluate(params, config \\ %{}) do
request_operation("signal/evaluate", params, config, &map_signal/1)
end
@doc """
Report whether the ACH transaction was initiated
Parameters
```
%{
client_transaction_id: "txn12345",
initiated: true,
days_funds_on_hold: 3,
decision_outcome: "APPROVE",
payment_method: "NEXT_DAY_ACH",
amount_instantly_available: 102.25
}
```
Response
```
{:ok, %{request_id: "a325fa"}}
```
"""
@spec report_decision(params, config) :: {:ok, map} | error
def report_decision(params, config \\ %{}) do
request_operation("signal/decision/report", params, config, &map_request_id/1)
end
@doc """
Report whether the ACH transaction was returned
Parameters
```
%{
client_transaction_id: "txn12345",
return_code: "R01",
returned_at: "2024-07-11T10:16:24Z"
}
```
Response
```
{:ok, %{request_id: "a325fa"}}
```
"""
@spec report_return(params, config) :: {:ok, map} | error
def report_return(params, config \\ %{}) do
request_operation("signal/return/report", params, config, &map_request_id/1)
end
@doc """
When Link is not initialized with Signal, call /signal/prepare to opt-in that
Item to the Signal data collection process, developing a Signal score.
If run on an Item that is already initialized with Signal,
this endpoint will return a 200 response and will not modify the Item.
Parameters
```
%{
access_token: 'access-sandbox-71e02f71-0960-4a27-abd2-5631e04f2175'
}
```
Response
```
{:ok, %{request_id: "a325fa"}}
```
"""
@spec prepare(params, config) :: {:ok, map} | error
def prepare(params, config \\ %{}) do
request_operation("signal/prepare", params, config, &map_request_id/1)
end
defp map_signal(body) do
Poison.Decode.transform(
body,
%{
as: %Plaid.Signal{
scores: %Plaid.Signal.Scores{
customer_initiated_return_risk: %Plaid.Signal.Scores.Risk{},
bank_initiated_return_risk: %Plaid.Signal.Scores.Risk{},
},
warnings: [%Plaid.Signal.Warning{}],
ruleset: %Plaid.Signal.Ruleset{}
}
}
)
end
defp map_request_id(%{"request_id" => r}) do
%{request_id: r}
end
defp request_operation(endpoint, params, config, mapper) do
c = config[:client] || Plaid
Request
|> struct(method: :post, endpoint: endpoint, body: params)
|> Request.add_metadata(config)
|> c.send_request(Client.new(config))
|> c.handle_response(mapper)
end
end