Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Commit

Permalink
Add get transactions by account
Browse files Browse the repository at this point in the history
  • Loading branch information
fernandoalmeida committed Apr 29, 2021
1 parent cfd1bbd commit 2807592
Show file tree
Hide file tree
Showing 3 changed files with 356 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Get all webhooks
- Get transactions by account

[unreleased]: https://github.com/brainnco/strong_params/compare/main
141 changes: 141 additions & 0 deletions lib/pluggy_elixir/transaction.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
defmodule PluggyElixir.Transaction do
@moduledoc """
TODO
"""

alias PluggyElixir.{Config, HttpClient}

defstruct [
:id,
:description,
:description_raw,
:currency_code,
:amount,
:date,
:balance,
:category,
:account_id,
:provider_code,
:status,
:payment_data
]

@type t :: %__MODULE__{
id: binary(),
description: binary(),
description_raw: binary(),
currency_code: binary(),
amount: float(),
date: NaiveDateTime.t(),
balance: float(),
category: binary(),
account_id: binary(),
provider_code: binary(),
status: binary(),
payment_data: payment_data()
}

@type payment_data :: %{
payer: identity(),
receiver: identity(),
reason: binary(),
payment_method: binary(),
reference_number: binary()
}

@type identity :: %{
type: binary(),
branch_number: binary(),
account_number: binary(),
routing_number: binary(),
document_number: document()
}

@type document :: %{
type: binary(),
value: binary()
}

@transactions_path "/transactions"
@default_page_size 20
@default_page_number 1

def all_by_account(params, config_overrides \\ [])

def all_by_account(%{account_id: _, from: _, to: _} = params, config_overrides) do
@transactions_path
|> HttpClient.get(format_params(params), Config.override(config_overrides))
|> handle_response
end

def all_by_account(_params, _config_overrides),
do: {:error, ":account_id, :from, and :to are required"}

defp handle_response({:ok, %{status: 200, body: body}}) do
result = %{
page: body["page"],
total_pages: body["totalPages"],
total: body["total"],
transactions: Enum.map(body["results"], &parse_transaction/1)
}

{:ok, result}
end

defp handle_response({:error, _reason} = error), do: error

defp format_params(params) do
[
accountId: params[:account_id],
from: params[:from],
to: params[:to],
pageSize: Map.get(params, :page_size, @default_page_size),
page: Map.get(params, :page, @default_page_number)
]
end

defp parse_transaction(transaction) do
%__MODULE__{
id: transaction["id"],
description: transaction["description"],
description_raw: transaction["descriptionRaw"],
currency_code: transaction["currencyCode"],
amount: parse_float(transaction["amount"]),
date: NaiveDateTime.from_iso8601!(transaction["date"]),
balance: parse_float(transaction["balance"]),
category: transaction["category"],
account_id: transaction["accountId"],
provider_code: transaction["providerCode"],
status: transaction["status"],
payment_data: parse_payment_data(transaction["paymentData"])
}
end

defp parse_payment_data(nil), do: nil

defp parse_payment_data(payment_data) do
%{
payer: parse_identity(payment_data["payer"]),
receiver: parse_identity(payment_data["receiver"]),
reason: payment_data["reason"],
payment_method: payment_data["paymentMethod"],
reference_number: payment_data["referenceNumber"]
}
end

defp parse_identity(identity) do
%{
type: identity["type"],
branch_number: identity["branchNumber"],
account_number: identity["accountNumber"],
routing_number: identity["routingNumber"],
document_number: %{
type: get_in(identity, ["documentNumber", "type"]),
value: get_in(identity, ["documentNumber", "value"])
}
}
end

defp parse_float(number) when is_float(number), do: number
defp parse_float(number), do: "#{number}" |> Float.parse() |> elem(0)
end
214 changes: 214 additions & 0 deletions test/pluggy_elixir/transaction_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
defmodule PluggyElixir.TransactionTest do
use PluggyElixir.Case

alias PluggyElixir.Transaction
alias PluggyElixir.HttpClient.Error

describe "all_by_account/4" do
test "list transactions of an account and period", %{bypass: bypass} do
params = %{
account_id: "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
from: ~D[2020-01-01],
to: ~D[2020-02-01]
}

config_overrides = [host: "http://localhost:#{bypass.port}"]

create_and_save_api_key()

bypass_expect(bypass, "GET", "/transactions", fn conn ->
assert conn.query_params == %{
"accountId" => "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
"from" => "2020-01-01",
"sandbox" => "true",
"to" => "2020-02-01",
"pageSize" => "20",
"page" => "1"
}

Conn.resp(
conn,
200,
~s<{"total": 3, "totalPages": 1, "page": 1, "results": [{"id": "5d6b9f9a-06aa-491f-926a-15ba46c6366d", "accountId": "03cc0eff-4ec5-495c-adb3-1ef9611624fc", "description": "Rappi", "currencyCode": "BRL", "amount": 41.58, "date": "2020-06-08T00:00:00.000Z", "balance": 41.58, "category": "Online Payment", "status": "POSTED"}, {"id": "6ec156fe-e8ac-4d9a-a4b3-7770529ab01c", "description": "TED Example", "descriptionRaw": null, "currencyCode": "BRL", "amount": 1500, "date": "2021-04-12T00:00:00.000Z", "balance": 3000, "category": "Transfer", "accountId": "03cc0eff-4ec5-495c-adb3-1ef9611624fc", "providerCode": "123", "status": "POSTED", "paymentData": {"payer": {"name": "Tiago Rodrigues Santos", "branchNumber": "090", "accountNumber": "1234-5", "routingNumber": "001", "documentNumber": {"type": "CPF", "value": "882.937.076-23"}}, "reason": "Taxa de serviço", "receiver": {"name": "Pluggy", "branchNumber": "999", "accountNumber": "9876-1", "routingNumber": "002", "documentNumber": {"type": "CNPJ", "value": "08.050.608/0001-32"}}, "paymentMethod": "TED", "referenceNumber": "123456789"}}]} >
)
end)

assert {:ok, result} = Transaction.all_by_account(params, config_overrides)

assert result == %{
page: 1,
total: 3,
total_pages: 1,
transactions: [
%Transaction{
account_id: "03cc0eff-4ec5-495c-adb3-1ef9611624fc",
amount: 41.58,
balance: 41.58,
category: "Online Payment",
currency_code: "BRL",
date: ~N[2020-06-08 00:00:00.000],
description: "Rappi",
description_raw: nil,
id: "5d6b9f9a-06aa-491f-926a-15ba46c6366d",
payment_data: nil,
provider_code: nil,
status: "POSTED"
},
%Transaction{
account_id: "03cc0eff-4ec5-495c-adb3-1ef9611624fc",
amount: 1_500,
balance: 3_000,
category: "Transfer",
currency_code: "BRL",
date: ~N[2021-04-12 00:00:00.000],
description: "TED Example",
description_raw: nil,
id: "6ec156fe-e8ac-4d9a-a4b3-7770529ab01c",
payment_data: %{
payer: %{
account_number: "1234-5",
branch_number: "090",
document_number: %{
type: "CPF",
value: "882.937.076-23"
},
routing_number: "001",
type: nil
},
payment_method: "TED",
reason: "Taxa de serviço",
receiver: %{
account_number: "9876-1",
branch_number: "999",
document_number: %{
type: "CNPJ",
value: "08.050.608/0001-32"
},
routing_number: "002",
type: nil
},
reference_number: "123456789"
},
provider_code: "123",
status: "POSTED"
}
]
}
end

test "allow custom pagination", %{bypass: bypass} do
params = %{
account_id: "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
from: ~D[2020-01-01],
to: ~D[2020-02-01],
page_size: 1,
page: 2
}

config_overrides = [host: "http://localhost:#{bypass.port}"]

create_and_save_api_key()

bypass_expect(bypass, "GET", "/transactions", fn conn ->
assert conn.query_params == %{
"accountId" => "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
"from" => "2020-01-01",
"sandbox" => "true",
"to" => "2020-02-01",
"pageSize" => "1",
"page" => "2"
}

Conn.resp(
conn,
200,
~s<{"total": 3, "totalPages": 3, "page": 2, "results": [{"id": "5d6b9f9a-06aa-491f-926a-15ba46c6366d", "accountId": "03cc0eff-4ec5-495c-adb3-1ef9611624fc", "description": "Rappi", "currencyCode": "BRL", "amount": 41.58, "date": "2020-06-08T00:00:00.000Z", "balance": 41.58, "category": "Online Payment", "status": "POSTED"}]}>
)
end)

assert {:ok, result} = Transaction.all_by_account(params, config_overrides)

assert result == %{
page: 2,
total: 3,
total_pages: 3,
transactions: [
%Transaction{
account_id: "03cc0eff-4ec5-495c-adb3-1ef9611624fc",
amount: 41.58,
balance: 41.58,
category: "Online Payment",
currency_code: "BRL",
date: ~N[2020-06-08 00:00:00.000],
description: "Rappi",
description_raw: nil,
id: "5d6b9f9a-06aa-491f-926a-15ba46c6366d",
payment_data: nil,
provider_code: nil,
status: "POSTED"
}
]
}
end

test "handle empty results", %{bypass: bypass} do
params = %{
account_id: "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
from: "invalid-date",
to: ~D[2020-02-01]
}

config_overrides = [host: "http://localhost:#{bypass.port}"]

create_and_save_api_key()

bypass_expect(bypass, "GET", "/transactions", fn conn ->
Conn.resp(conn, 200, ~s<{"total": 0, "totalPages": 0, "page": 1, "results": []}>)
end)

assert {:ok, result} = Transaction.all_by_account(params, config_overrides)

assert result == %{
page: 1,
total: 0,
total_pages: 0,
transactions: []
}
end

test "when params are invalid, returns a validation error" do
invalid_params = %{}

assert Transaction.all_by_account(invalid_params) ==
{:error, ":account_id, :from, and :to are required"}
end

test "when has error to get transactions list, returns that error", %{bypass: bypass} do
params = %{
account_id: "invalid-account-id",
from: "invalid-date",
to: ~D[2020-02-01]
}

config_overrides = [host: "http://localhost:#{bypass.port}"]

create_and_save_api_key()

bypass_expect(bypass, "GET", "/transactions", fn conn ->
Conn.resp(
conn,
500,
~s<{"message": "There was an error processing your request", "code": 500}>
)
end)

assert {:error, reason} = Transaction.all_by_account(params, config_overrides)

assert reason == %Error{
code: 500,
details: nil,
message: "There was an error processing your request"
}
end
end
end

0 comments on commit 2807592

Please sign in to comment.