-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from starkbank/feature/approval
Feature/approval
- Loading branch information
Showing
11 changed files
with
359 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
defmodule StarkBank.PaymentRequest do | ||
alias __MODULE__, as: PaymentRequest | ||
alias StarkBank.Utils.Rest | ||
alias StarkBank.Utils.Check | ||
alias StarkBank.Utils.API | ||
alias StarkBank.User.Project | ||
alias StarkBank.Error | ||
alias StarkBank.Boleto, as: Boleto | ||
alias StarkBank.Transfer, as: Transfer | ||
alias StarkBank.Transaction, as: Transaction | ||
alias StarkBank.BoletoPayment, as: BoletoPayment | ||
alias StarkBank.UtilityPayment, as: UtilityPayment | ||
|
||
@moduledoc """ | ||
Groups PaymentRequest related functions | ||
""" | ||
|
||
@doc """ | ||
A PaymentRequest is an indirect request to access a specific cash-out service | ||
(such as Transfer, BoletoPayments, etc.) which goes through the cost center | ||
approval flow on our web banking. To emit a PaymentRequest, you must direct it to | ||
a specific cost center by its ID, which can be retrieved on our web banking at the | ||
cost center page. | ||
## Parameters (required): | ||
- `:center_id` [string]: target cost center ID. ex: "5656565656565656" | ||
- `:payment` [Transfer, BoletoPayment, UtilityPayment, Transaction or map]: payment entity that should be approved and executed. | ||
## Parameters (conditionally required): | ||
- `:type` [string]: payment type, inferred from the payment parameter if it is not a map. ex: "transfer", "boleto-payment" | ||
## Parameters (optional): | ||
- `:due` [Date, DateTime, Time or string]: Payment target date in ISO format. ex: 2020-12-31 | ||
- `:tags` [list of strings]: list of strings for tagging | ||
## Attributes (return-only): | ||
- `:id` [string, default nil]: unique id returned when PaymentRequest is created. ex: "5656565656565656" | ||
- `:amount` [integer, default nil]: PaymentRequest amount. ex: 100000 = R$1.000,00 | ||
- `:status` [string, default nil]: current PaymentRequest status.ex: "pending" or "approved" | ||
- `:actions` [list of maps, default nil]: list of actions that are affecting this PaymentRequest. ex: [%{"type": "member", "id": "56565656565656, "action": "requested"}] | ||
- `:updated` [DateTime, default nil]: latest update datetime for the PaymentRequest. ex: 2020-12-31 | ||
- `:created` [DateTime, default nil]: creation datetime for the PaymentRequest. ex: 2020-12-31 | ||
""" | ||
|
||
@enforce_keys [:center_id, :payment] | ||
defstruct [ | ||
:id, | ||
:payment, | ||
:center_id, | ||
:due, | ||
:tags, | ||
:amount, | ||
:status, | ||
:actions, | ||
:updated, | ||
:created, | ||
:type | ||
] | ||
|
||
@type t() :: %__MODULE__{} | ||
|
||
@doc """ | ||
Sends a list of PaymentRequests structs for creating in the Stark Bank API | ||
## Paramenters (required): | ||
- `payment_requests` [list of PaymentRequest structs]: list of PaymentRequest objects to be created in the API | ||
## Options: | ||
- `:user` [Project]: Project struct returned from StarkBank.project(). Only necessary if default project has not been set in configs. | ||
## Return: | ||
- list of PaymentRequest structs with updated attributes | ||
""" | ||
@spec create([PaymentRequest.t() | map()], user: Project.t() | nil) :: | ||
{:ok, [PaymentRequest.t()]} | {:error, [Error.t()]} | ||
def create(payment_requests, options \\ []) do | ||
case Rest.post( | ||
resource(), | ||
Enum.map(payment_requests, fn request -> %PaymentRequest{request | type: get_type(request.payment)} end), | ||
options | ||
) do | ||
{:ok, requests} -> {:ok, requests |> Enum.map(&parse_request!/1)} | ||
response -> response | ||
end | ||
end | ||
|
||
@doc """ | ||
Same as create(), but it will unwrap the error tuple and raise in case of errors. | ||
""" | ||
@spec create!([PaymentRequest.t() | map()], user: Project.t() | nil) :: any | ||
def create!(payment_requests, options \\ []) do | ||
Rest.post!( | ||
resource(), | ||
Enum.map(payment_requests, fn request -> %PaymentRequest{request | type: get_type(request.payment)} end), | ||
options | ||
) |> Enum.map(&parse_request!/1) | ||
end | ||
|
||
@doc """ | ||
Receive a stream of PaymentRequest structs previously created by this user in the Stark Bank API | ||
## Options: | ||
- `:limit` [integer, default nil]: maximum number of structs to be retrieved. Unlimited if nil. ex: 35 | ||
- `:after` [Date, DateTime or string, default nil]: date filter for structs created only after specified date. ex: ~D[2020-03-25] | ||
- `:before` [Date, DateTime or string, default nil]: date filter for structs created only before specified date. ex: ~D[2020-03-25] | ||
- `:sort` [string, default "-created"]: sort order considered in response. Valid options are "-created" or "-due". | ||
- `:status` [string, default nil]: filter for status of retrieved structs. ex: "paid" or "registered" | ||
- `:type` [string, default nil]: payment type, inferred from the payment parameter if it is not a dictionary. ex: "transfer", "boleto-payment" | ||
- `:tags` [list of strings, default nil]: tags to filter retrieved structs. ex: ["tony", "stark"] | ||
- `:ids` [list of strings, default nil]: list of ids to filter retrieved structs. ex: ["5656565656565656", "4545454545454545"] | ||
- `:user` [Project]: Project struct returned from StarkBank.project(). Only necessary if default project has not been set in configs. | ||
## Return: | ||
- stream of PaymentRequest structs with updated attributes | ||
""" | ||
@spec query( | ||
limit: integer, | ||
after: Date.t() | DateTime.t() | binary, | ||
before: Date.t() | DateTime.t() | binary, | ||
sort: binary, | ||
status: binary, | ||
type: binary, | ||
tags: [binary], | ||
ids: [binary], | ||
user: Project.t() | ||
) :: | ||
({:cont, {:ok, [PaymentRequest.t()]}} | ||
| {:error, [Error.t()]} | ||
| {:halt, any} | ||
| {:suspend, any}, | ||
any -> | ||
any) | ||
def query(options \\ []) do | ||
Rest.get_list(resource(), options) |> Enum.map(&parse_request/1) | ||
end | ||
|
||
@doc """ | ||
Same as query(), but it will unwrap the error tuple and raise in case of errors. | ||
""" | ||
@spec query!( | ||
limit: integer, | ||
after: Date.t() | DateTime.t() | binary, | ||
before: Date.t() | DateTime.t() | binary, | ||
sort: binary, | ||
status: binary, | ||
type: binary, | ||
tags: [binary], | ||
ids: [binary], | ||
user: Project.t() | ||
) :: | ||
({:cont, [PaymentRequest.t()]} | {:halt, any} | {:suspend, any}, any -> any) | ||
def query!(options \\ []) do | ||
Rest.get_list!(resource(), options) |> Enum.map(&parse_request!/1) | ||
end | ||
|
||
defp get_type(resource) do | ||
case resource do | ||
%Transfer{} -> "transfer" | ||
%Transaction{} -> "transaction" | ||
%BoletoPayment{} -> "boleto-payment" | ||
%UtilityPayment{} -> "utility-payment" | ||
end | ||
end | ||
|
||
defp parse_request(request_tuple) do | ||
case request_tuple do | ||
{:ok, request} -> {:ok, parse_request!(request)} | ||
_ -> request_tuple | ||
end | ||
end | ||
|
||
defp parse_request!(request) do | ||
%PaymentRequest{request | payment: request.payment |> API.from_api_json(resource_maker_by_type(request.type))} | ||
rescue | ||
CaseClauseError -> request | ||
end | ||
|
||
defp resource_maker_by_type(subscription) do | ||
case subscription do | ||
"transfer" -> &Transfer.resource_maker/1 | ||
"transaction" -> &Transaction.resource_maker/1 | ||
"boleto" -> &Boleto.resource_maker/1 | ||
"boleto-payment" -> &BoletoPayment.resource_maker/1 | ||
"utility-payment" -> &UtilityPayment.resource_maker/1 | ||
end | ||
end | ||
|
||
@doc false | ||
def resource() do | ||
{ | ||
"PaymentRequest", | ||
&resource_maker/1 | ||
} | ||
end | ||
|
||
@doc false | ||
def resource_maker(json) do | ||
%PaymentRequest{ | ||
id: json[:id], | ||
payment: json[:payment], | ||
center_id: json[:center_id], | ||
type: json[:type], | ||
tags: json[:tags], | ||
amount: json[:amount], | ||
status: json[:status], | ||
actions: json[:actions], | ||
updated: json[:updated] |> Check.datetime(), | ||
created: json[:created] |> Check.datetime(), | ||
due: json[:due] |> Check.datetime() | ||
} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
defmodule StarkBankTest.PaymentRequest do | ||
use ExUnit.Case | ||
|
||
@tag :payment_request | ||
test "create! PaymentRequest" do | ||
requests = for i <- 1..10, i > 0 do | ||
request_example() | ||
end | ||
received = StarkBank.PaymentRequest.create!(requests) | ||
for item <- received do | ||
assert !is_nil(item.id) | ||
end | ||
end | ||
|
||
@tag :payment_request | ||
test "create PaymentRequest" do | ||
requests = for i <- 1..10, i > 0 do | ||
request_example() | ||
end | ||
{:ok, received} = StarkBank.PaymentRequest.create(requests) | ||
for item <- received do | ||
assert !is_nil(item.id) | ||
end | ||
end | ||
|
||
@tag :payment_request | ||
test "query payment request" do | ||
StarkBank.PaymentRequest.query(center_id: System.get_env("SANDBOX_CENTER_ID"), limit: 101, before: DateTime.utc_now()) | ||
|> Enum.take(200) | ||
|> (fn list -> assert length(list) <= 101 end).() | ||
end | ||
|
||
@tag :payment_request | ||
test "query! payment request" do | ||
StarkBank.PaymentRequest.query!(center_id: System.get_env("SANDBOX_CENTER_ID"), limit: 101, before: DateTime.utc_now()) | ||
|> Enum.take(200) | ||
|> (fn list -> assert length(list) <= 101 end).() | ||
end | ||
|
||
def request_example() do | ||
payment = create_payment() | ||
%StarkBank.PaymentRequest{ | ||
center_id: System.get_env("SANDBOX_CENTER_ID"), | ||
payment: payment, | ||
due: get_due_date(payment) | ||
} | ||
end | ||
|
||
defp get_days() do | ||
days = Enum.random(1..7) | ||
Date.utc_today() |> Date.add(days) | ||
end | ||
|
||
defp get_due_date(payment) do | ||
case payment do | ||
%StarkBank.Transfer{} -> get_days() | ||
%StarkBank.BoletoPayment{} -> get_days() | ||
%StarkBank.UtilityPayment{} -> get_days() | ||
%StarkBank.Transaction{} -> nil | ||
end | ||
end | ||
|
||
defp create_payment() do | ||
case Enum.random(0..3) do | ||
0 -> StarkBankTest.Transfer.example_transfer(false) | ||
1 -> StarkBankTest.Transaction.example_transaction() | ||
2 -> StarkBankTest.BoletoPayment.example_payment(false) | ||
3 -> StarkBankTest.UtilityPayment.example_payment(false) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.