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

Commit 2807592

Browse files
Add get transactions by account
1 parent cfd1bbd commit 2807592

File tree

3 files changed

+356
-0
lines changed

3 files changed

+356
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- Get all webhooks
13+
- Get transactions by account
1314

1415
[unreleased]: https://github.com/brainnco/strong_params/compare/main

lib/pluggy_elixir/transaction.ex

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
defmodule PluggyElixir.Transaction do
2+
@moduledoc """
3+
TODO
4+
"""
5+
6+
alias PluggyElixir.{Config, HttpClient}
7+
8+
defstruct [
9+
:id,
10+
:description,
11+
:description_raw,
12+
:currency_code,
13+
:amount,
14+
:date,
15+
:balance,
16+
:category,
17+
:account_id,
18+
:provider_code,
19+
:status,
20+
:payment_data
21+
]
22+
23+
@type t :: %__MODULE__{
24+
id: binary(),
25+
description: binary(),
26+
description_raw: binary(),
27+
currency_code: binary(),
28+
amount: float(),
29+
date: NaiveDateTime.t(),
30+
balance: float(),
31+
category: binary(),
32+
account_id: binary(),
33+
provider_code: binary(),
34+
status: binary(),
35+
payment_data: payment_data()
36+
}
37+
38+
@type payment_data :: %{
39+
payer: identity(),
40+
receiver: identity(),
41+
reason: binary(),
42+
payment_method: binary(),
43+
reference_number: binary()
44+
}
45+
46+
@type identity :: %{
47+
type: binary(),
48+
branch_number: binary(),
49+
account_number: binary(),
50+
routing_number: binary(),
51+
document_number: document()
52+
}
53+
54+
@type document :: %{
55+
type: binary(),
56+
value: binary()
57+
}
58+
59+
@transactions_path "/transactions"
60+
@default_page_size 20
61+
@default_page_number 1
62+
63+
def all_by_account(params, config_overrides \\ [])
64+
65+
def all_by_account(%{account_id: _, from: _, to: _} = params, config_overrides) do
66+
@transactions_path
67+
|> HttpClient.get(format_params(params), Config.override(config_overrides))
68+
|> handle_response
69+
end
70+
71+
def all_by_account(_params, _config_overrides),
72+
do: {:error, ":account_id, :from, and :to are required"}
73+
74+
defp handle_response({:ok, %{status: 200, body: body}}) do
75+
result = %{
76+
page: body["page"],
77+
total_pages: body["totalPages"],
78+
total: body["total"],
79+
transactions: Enum.map(body["results"], &parse_transaction/1)
80+
}
81+
82+
{:ok, result}
83+
end
84+
85+
defp handle_response({:error, _reason} = error), do: error
86+
87+
defp format_params(params) do
88+
[
89+
accountId: params[:account_id],
90+
from: params[:from],
91+
to: params[:to],
92+
pageSize: Map.get(params, :page_size, @default_page_size),
93+
page: Map.get(params, :page, @default_page_number)
94+
]
95+
end
96+
97+
defp parse_transaction(transaction) do
98+
%__MODULE__{
99+
id: transaction["id"],
100+
description: transaction["description"],
101+
description_raw: transaction["descriptionRaw"],
102+
currency_code: transaction["currencyCode"],
103+
amount: parse_float(transaction["amount"]),
104+
date: NaiveDateTime.from_iso8601!(transaction["date"]),
105+
balance: parse_float(transaction["balance"]),
106+
category: transaction["category"],
107+
account_id: transaction["accountId"],
108+
provider_code: transaction["providerCode"],
109+
status: transaction["status"],
110+
payment_data: parse_payment_data(transaction["paymentData"])
111+
}
112+
end
113+
114+
defp parse_payment_data(nil), do: nil
115+
116+
defp parse_payment_data(payment_data) do
117+
%{
118+
payer: parse_identity(payment_data["payer"]),
119+
receiver: parse_identity(payment_data["receiver"]),
120+
reason: payment_data["reason"],
121+
payment_method: payment_data["paymentMethod"],
122+
reference_number: payment_data["referenceNumber"]
123+
}
124+
end
125+
126+
defp parse_identity(identity) do
127+
%{
128+
type: identity["type"],
129+
branch_number: identity["branchNumber"],
130+
account_number: identity["accountNumber"],
131+
routing_number: identity["routingNumber"],
132+
document_number: %{
133+
type: get_in(identity, ["documentNumber", "type"]),
134+
value: get_in(identity, ["documentNumber", "value"])
135+
}
136+
}
137+
end
138+
139+
defp parse_float(number) when is_float(number), do: number
140+
defp parse_float(number), do: "#{number}" |> Float.parse() |> elem(0)
141+
end
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
defmodule PluggyElixir.TransactionTest do
2+
use PluggyElixir.Case
3+
4+
alias PluggyElixir.Transaction
5+
alias PluggyElixir.HttpClient.Error
6+
7+
describe "all_by_account/4" do
8+
test "list transactions of an account and period", %{bypass: bypass} do
9+
params = %{
10+
account_id: "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
11+
from: ~D[2020-01-01],
12+
to: ~D[2020-02-01]
13+
}
14+
15+
config_overrides = [host: "http://localhost:#{bypass.port}"]
16+
17+
create_and_save_api_key()
18+
19+
bypass_expect(bypass, "GET", "/transactions", fn conn ->
20+
assert conn.query_params == %{
21+
"accountId" => "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
22+
"from" => "2020-01-01",
23+
"sandbox" => "true",
24+
"to" => "2020-02-01",
25+
"pageSize" => "20",
26+
"page" => "1"
27+
}
28+
29+
Conn.resp(
30+
conn,
31+
200,
32+
~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"}}]} >
33+
)
34+
end)
35+
36+
assert {:ok, result} = Transaction.all_by_account(params, config_overrides)
37+
38+
assert result == %{
39+
page: 1,
40+
total: 3,
41+
total_pages: 1,
42+
transactions: [
43+
%Transaction{
44+
account_id: "03cc0eff-4ec5-495c-adb3-1ef9611624fc",
45+
amount: 41.58,
46+
balance: 41.58,
47+
category: "Online Payment",
48+
currency_code: "BRL",
49+
date: ~N[2020-06-08 00:00:00.000],
50+
description: "Rappi",
51+
description_raw: nil,
52+
id: "5d6b9f9a-06aa-491f-926a-15ba46c6366d",
53+
payment_data: nil,
54+
provider_code: nil,
55+
status: "POSTED"
56+
},
57+
%Transaction{
58+
account_id: "03cc0eff-4ec5-495c-adb3-1ef9611624fc",
59+
amount: 1_500,
60+
balance: 3_000,
61+
category: "Transfer",
62+
currency_code: "BRL",
63+
date: ~N[2021-04-12 00:00:00.000],
64+
description: "TED Example",
65+
description_raw: nil,
66+
id: "6ec156fe-e8ac-4d9a-a4b3-7770529ab01c",
67+
payment_data: %{
68+
payer: %{
69+
account_number: "1234-5",
70+
branch_number: "090",
71+
document_number: %{
72+
type: "CPF",
73+
value: "882.937.076-23"
74+
},
75+
routing_number: "001",
76+
type: nil
77+
},
78+
payment_method: "TED",
79+
reason: "Taxa de serviço",
80+
receiver: %{
81+
account_number: "9876-1",
82+
branch_number: "999",
83+
document_number: %{
84+
type: "CNPJ",
85+
value: "08.050.608/0001-32"
86+
},
87+
routing_number: "002",
88+
type: nil
89+
},
90+
reference_number: "123456789"
91+
},
92+
provider_code: "123",
93+
status: "POSTED"
94+
}
95+
]
96+
}
97+
end
98+
99+
test "allow custom pagination", %{bypass: bypass} do
100+
params = %{
101+
account_id: "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
102+
from: ~D[2020-01-01],
103+
to: ~D[2020-02-01],
104+
page_size: 1,
105+
page: 2
106+
}
107+
108+
config_overrides = [host: "http://localhost:#{bypass.port}"]
109+
110+
create_and_save_api_key()
111+
112+
bypass_expect(bypass, "GET", "/transactions", fn conn ->
113+
assert conn.query_params == %{
114+
"accountId" => "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
115+
"from" => "2020-01-01",
116+
"sandbox" => "true",
117+
"to" => "2020-02-01",
118+
"pageSize" => "1",
119+
"page" => "2"
120+
}
121+
122+
Conn.resp(
123+
conn,
124+
200,
125+
~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"}]}>
126+
)
127+
end)
128+
129+
assert {:ok, result} = Transaction.all_by_account(params, config_overrides)
130+
131+
assert result == %{
132+
page: 2,
133+
total: 3,
134+
total_pages: 3,
135+
transactions: [
136+
%Transaction{
137+
account_id: "03cc0eff-4ec5-495c-adb3-1ef9611624fc",
138+
amount: 41.58,
139+
balance: 41.58,
140+
category: "Online Payment",
141+
currency_code: "BRL",
142+
date: ~N[2020-06-08 00:00:00.000],
143+
description: "Rappi",
144+
description_raw: nil,
145+
id: "5d6b9f9a-06aa-491f-926a-15ba46c6366d",
146+
payment_data: nil,
147+
provider_code: nil,
148+
status: "POSTED"
149+
}
150+
]
151+
}
152+
end
153+
154+
test "handle empty results", %{bypass: bypass} do
155+
params = %{
156+
account_id: "d619cfde-a8d7-4fe0-a10d-6de488bde4e0",
157+
from: "invalid-date",
158+
to: ~D[2020-02-01]
159+
}
160+
161+
config_overrides = [host: "http://localhost:#{bypass.port}"]
162+
163+
create_and_save_api_key()
164+
165+
bypass_expect(bypass, "GET", "/transactions", fn conn ->
166+
Conn.resp(conn, 200, ~s<{"total": 0, "totalPages": 0, "page": 1, "results": []}>)
167+
end)
168+
169+
assert {:ok, result} = Transaction.all_by_account(params, config_overrides)
170+
171+
assert result == %{
172+
page: 1,
173+
total: 0,
174+
total_pages: 0,
175+
transactions: []
176+
}
177+
end
178+
179+
test "when params are invalid, returns a validation error" do
180+
invalid_params = %{}
181+
182+
assert Transaction.all_by_account(invalid_params) ==
183+
{:error, ":account_id, :from, and :to are required"}
184+
end
185+
186+
test "when has error to get transactions list, returns that error", %{bypass: bypass} do
187+
params = %{
188+
account_id: "invalid-account-id",
189+
from: "invalid-date",
190+
to: ~D[2020-02-01]
191+
}
192+
193+
config_overrides = [host: "http://localhost:#{bypass.port}"]
194+
195+
create_and_save_api_key()
196+
197+
bypass_expect(bypass, "GET", "/transactions", fn conn ->
198+
Conn.resp(
199+
conn,
200+
500,
201+
~s<{"message": "There was an error processing your request", "code": 500}>
202+
)
203+
end)
204+
205+
assert {:error, reason} = Transaction.all_by_account(params, config_overrides)
206+
207+
assert reason == %Error{
208+
code: 500,
209+
details: nil,
210+
message: "There was an error processing your request"
211+
}
212+
end
213+
end
214+
end

0 commit comments

Comments
 (0)