Skip to content

Commit 494de6d

Browse files
committed
Process OpenPix withdraw transactions
1 parent b846d7f commit 494de6d

File tree

5 files changed

+125
-45
lines changed

5 files changed

+125
-45
lines changed

thebook/webhooks/management/commands/fetch_openpix_transactions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Command(BaseCommand):
1010

1111
def handle(self, *args, **options):
1212
"""If we miss some webhook payload, this command should ensure that we don't lose any transaction"""
13-
end_date = datetime.date.today()
13+
end_date = datetime.date.today() + datetime.timedelta(days=1)
1414
start_date = end_date - datetime.timedelta(days=2)
1515

1616
transactions = fetch_transactions(start_date, end_date)

thebook/webhooks/models.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,15 @@ def process(self, bank_account=None, user=None):
6767
self.save()
6868
return
6969

70-
if jmespath.search("event", payload) != "OPENPIX:TRANSACTION_RECEIVED":
70+
transaction_type = jmespath.search("event", payload)
71+
if transaction_type != "OPENPIX:TRANSACTION_RECEIVED":
7172
self.status = ProcessingStatus.UNPARSABLE
7273
self.internal_notes = "webhooks.paypal.unparsable_event"
7374
self.save()
7475
return
7576

7677
amount = jmespath.search("pix.charge.value || pix.value", payload) / 100
77-
openpix_fee = calculate_openpix_fee(amount)
78+
openpix_fee = calculate_openpix_fee(amount, transaction_type)
7879

7980
# Original in UTC time
8081
paid_at = jmespath.search("pix.charge.paidAt || pix.time", payload)

thebook/webhooks/openpix/services.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@
1010
from thebook.bookkeeping.models import BankAccount, Category, Transaction
1111

1212

13-
def calculate_openpix_fee(amount):
14-
"""OpenPix doesn't provide the fee in the Webhook payload so we need to calculate it based on the amount received and the active account plan"""
13+
def calculate_openpix_fee(amount, transaction_type):
14+
"""
15+
OpenPix doesn't provide the fee in the Webhook payload so we need to calculate it based
16+
on the amount received, the active account plan and the type of the transaction
17+
"""
1518
fee = 0.0
1619

17-
if settings.OPENPIX_PLAN == "FIXO":
20+
if transaction_type == "WITHDRAW":
21+
fee = -1
22+
elif settings.OPENPIX_PLAN == "FIXO":
1823
fee = -0.85
1924
elif settings.OPENPIX_PLAN == "PERCENTUAL":
2025
fee = -1 * round(min(max(0.008 * amount, 0.5), 5), 2)
@@ -68,6 +73,7 @@ def fetch_transactions(start_date: datetime.date, end_date: datetime.date):
6873
transaction_description = (
6974
f"Transferência entre contas bancárias - {transaction_id}"
7075
)
76+
transaction_amount = -1 * transaction_amount
7177
else:
7278
transaction_category = None
7379
payer_name = jmespath.search("payer.name", transaction) or ""
@@ -86,19 +92,20 @@ def fetch_transactions(start_date: datetime.date, end_date: datetime.date):
8692
)
8793
)
8894

89-
if not is_bank_account_transfer:
90-
transaction_fee_amount = calculate_openpix_fee(transaction_amount)
91-
92-
results.append(
93-
Transaction(
94-
reference=f"{transaction_id}-T",
95-
date=transaction_date,
96-
description=f"Taxa OpenPix - {transaction_description}",
97-
amount=transaction_fee_amount,
98-
bank_account=bank_account,
99-
category=bank_fee_category,
100-
created_by=user,
101-
)
95+
transaction_fee_amount = calculate_openpix_fee(
96+
transaction_amount, transaction_type
97+
)
98+
99+
results.append(
100+
Transaction(
101+
reference=f"{transaction_id}-T",
102+
date=transaction_date,
103+
description=f"Taxa OpenPix - {transaction_description}",
104+
amount=transaction_fee_amount,
105+
bank_account=bank_account,
106+
category=bank_fee_category,
107+
created_by=user,
102108
)
109+
)
103110

104111
return results

thebook/webhooks/tests/openpix/test_calculate_openpix_fee.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,28 @@
66

77

88
@pytest.mark.parametrize(
9-
"openpix_plan,amount,expected_fee",
9+
"openpix_plan,transaction_type,amount,expected_fee",
1010
[
11-
("PERCENTUAL", 20, -0.5),
12-
("PERCENTUAL", 62.5, -0.5),
13-
("PERCENTUAL", 64, -0.51),
14-
("PERCENTUAL", 100, -0.8),
15-
("PERCENTUAL", 625, -5),
16-
("PERCENTUAL", 630, -5),
17-
("FIXO", 20, -0.85),
18-
("FIXO", 62.50, -0.85),
19-
("FIXO", 64, -0.85),
20-
("FIXO", 100, -0.85),
21-
("FIXO", 625, -0.85),
22-
("FIXO", 630, -0.85),
11+
("PERCENTUAL", "OPENPIX:TRANSACTION_RECEIVED", 20, -0.5),
12+
("PERCENTUAL", "PAYMENT", 62.5, -0.5),
13+
("PERCENTUAL", "PAYMENT", 64, -0.51),
14+
("PERCENTUAL", "PAYMENT", 100, -0.8),
15+
("PERCENTUAL", "PAYMENT", 625, -5),
16+
("PERCENTUAL", "PAYMENT", 630, -5),
17+
("FIXO", "OPENPIX:TRANSACTION_RECEIVED", 20, -0.85),
18+
("FIXO", "PAYMENT", 62.50, -0.85),
19+
("FIXO", "PAYMENT", 64, -0.85),
20+
("FIXO", "PAYMENT", 100, -0.85),
21+
("FIXO", "PAYMENT", 625, -0.85),
22+
("FIXO", "PAYMENT", 630, -0.85),
23+
("PERCENTUAL", "WITHDRAW", 630, -1),
24+
("FIXO", "WITHDRAW", 630, -1),
2325
],
2426
)
2527
def test_calculate_openpix_fee_based_on_selected_plan(
26-
settings, openpix_plan, amount, expected_fee
28+
settings, openpix_plan, transaction_type, amount, expected_fee
2729
):
2830
settings.OPENPIX_PLAN = openpix_plan
29-
assert calculate_openpix_fee(amount) == round(Decimal(expected_fee), 2)
31+
assert calculate_openpix_fee(amount, transaction_type) == round(
32+
Decimal(expected_fee), 2
33+
)

thebook/webhooks/tests/openpix/test_services__fetch_transactions.py

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ def openpix_fetch_transactions__one_transaction():
6565
return payload.read()
6666

6767

68+
@pytest.fixture
69+
def openpix_fetch_transactions__withdraw_transaction():
70+
with open(
71+
Path(
72+
SAMPLE_PAYLOADS_DIR
73+
/ "openpix_fetch_transactions__withdraw_transaction.json"
74+
),
75+
"r",
76+
) as payload:
77+
return payload.read()
78+
79+
6880
@responses.activate
6981
def test_fetch_multiple_transactions(
7082
db,
@@ -87,7 +99,7 @@ def test_fetch_multiple_transactions(
8799
start_date=datetime.date(2026, 2, 1), end_date=datetime.date(2026, 2, 28)
88100
)
89101

90-
assert len(transactions) == 5
102+
assert len(transactions) == 6
91103

92104
assert transactions[0].reference == "01KH7WTFXGGFDSJKHFKJSDHGDG"
93105
assert transactions[0].date == datetime.date(2026, 2, 15)
@@ -111,27 +123,38 @@ def test_fetch_multiple_transactions(
111123
transactions[2].description
112124
== "Transferência entre contas bancárias - E54811417202602091301r0gglTvTqLN"
113125
)
114-
assert transactions[2].amount == Decimal("511.87")
126+
assert transactions[2].amount == Decimal("-511.87")
115127
assert transactions[2].bank_account == openpix_bank_account
116128
assert transactions[2].category == bank_account_transfer_category
117129
assert transactions[2].created_by == user
118130

119-
assert transactions[3].reference == "MTBQL"
120-
assert transactions[3].date == datetime.date(2026, 2, 28)
121-
assert transactions[3].description == "LUIZ ANTONIO - 12345678910"
122-
assert transactions[3].amount == Decimal("42")
131+
assert transactions[3].reference == "E54811417202602091301r0gglTvTqLN-T"
132+
assert transactions[3].date == datetime.date(2026, 2, 20)
133+
assert (
134+
transactions[3].description
135+
== "Taxa OpenPix - Transferência entre contas bancárias - E54811417202602091301r0gglTvTqLN"
136+
)
137+
assert transactions[3].amount == Decimal("-1")
123138
assert transactions[3].bank_account == openpix_bank_account
124-
assert transactions[3].category == None
139+
assert transactions[3].category == bank_fee_category
125140
assert transactions[3].created_by == user
126141

127-
assert transactions[4].reference == "MTBQL-T"
142+
assert transactions[4].reference == "MTBQL"
128143
assert transactions[4].date == datetime.date(2026, 2, 28)
129-
assert transactions[4].description == "Taxa OpenPix - LUIZ ANTONIO - 12345678910"
130-
assert transactions[4].amount == Decimal("-0.50")
144+
assert transactions[4].description == "LUIZ ANTONIO - 12345678910"
145+
assert transactions[4].amount == Decimal("42")
131146
assert transactions[4].bank_account == openpix_bank_account
132-
assert transactions[4].category == bank_fee_category
147+
assert transactions[4].category == None
133148
assert transactions[4].created_by == user
134149

150+
assert transactions[5].reference == "MTBQL-T"
151+
assert transactions[5].date == datetime.date(2026, 2, 28)
152+
assert transactions[5].description == "Taxa OpenPix - LUIZ ANTONIO - 12345678910"
153+
assert transactions[5].amount == Decimal("-0.50")
154+
assert transactions[5].bank_account == openpix_bank_account
155+
assert transactions[5].category == bank_fee_category
156+
assert transactions[5].created_by == user
157+
135158

136159
@responses.activate
137160
def test_fetch_already_existing_transactions(
@@ -199,3 +222,48 @@ def test_do_not_return_webhook_processed_transactions(
199222
)
200223

201224
assert len(transactions) == 0
225+
226+
227+
@responses.activate
228+
def test_fetch_withdraw_transaction(
229+
db,
230+
openpix_fetch_transactions__withdraw_transaction,
231+
openpix_bank_account,
232+
bank_account_transfer_category,
233+
bank_fee_category,
234+
user,
235+
):
236+
responses.add(
237+
responses.GET,
238+
f"{settings.OPENPIX_API_BASE_URL}/api/v1/transaction",
239+
body=openpix_fetch_transactions__withdraw_transaction,
240+
content_type="application/json",
241+
)
242+
243+
transactions = fetch_transactions(
244+
start_date=datetime.date(2026, 2, 1), end_date=datetime.date(2026, 2, 28)
245+
)
246+
247+
assert len(transactions) == 2
248+
249+
assert transactions[0].reference == "E54811417202602091301r0gglTvTqLN"
250+
assert transactions[0].date == datetime.date(2026, 2, 20)
251+
assert (
252+
transactions[0].description
253+
== "Transferência entre contas bancárias - E54811417202602091301r0gglTvTqLN"
254+
)
255+
assert transactions[0].amount == Decimal("-511.87")
256+
assert transactions[0].bank_account == openpix_bank_account
257+
assert transactions[0].category == bank_account_transfer_category
258+
assert transactions[0].created_by == user
259+
260+
assert transactions[1].reference == "E54811417202602091301r0gglTvTqLN-T"
261+
assert transactions[1].date == datetime.date(2026, 2, 20)
262+
assert (
263+
transactions[1].description
264+
== "Taxa OpenPix - Transferência entre contas bancárias - E54811417202602091301r0gglTvTqLN"
265+
)
266+
assert transactions[1].amount == Decimal("-1")
267+
assert transactions[1].bank_account == openpix_bank_account
268+
assert transactions[1].category == bank_fee_category
269+
assert transactions[1].created_by == user

0 commit comments

Comments
 (0)