Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions barte/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,41 @@ def get_pix_qrcode(self, charge_id: str) -> PixCharge:
return from_dict(data_class=PixCharge, data=json_response, config=DACITE_CONFIG)

def refund_charge(self, charge_id: str, as_fraud: Optional[bool] = False) -> Charge:
"""Refund a charge"""
"""Refund a charge

Raises:
BarteError: When the API returns an error response with Barte error codes.
"""
json_response = self._request(
"PATCH", f"/v2/charges/{charge_id}/refund", json={"asFraud": as_fraud}
)

if "errors" in json_response:
error_response = from_dict(
data_class=ErrorResponse, data=json_response, config=DACITE_CONFIG
)
error_response.raise_exception(response=json_response)

return from_dict(data_class=Charge, data=json_response, config=DACITE_CONFIG)

def partial_refund_charge(self, charge_id: str, value: Decimal) -> List[Refund]:
"""Refund a charge partialy"""
def partial_refund_charge(
self, charge_id: str, value: Decimal
) -> List[PartialRefund]:
"""Refund a charge partialy

Raises:
BarteError: When the API returns an error response with Barte error codes.
"""
json_response = self._request(
"PATCH", f"/v2/charges/partial-refund/{charge_id}", json={"value": value}
)

if isinstance(json_response, dict) and "errors" in json_response:
error_response = from_dict(
data_class=ErrorResponse, data=json_response, config=DACITE_CONFIG
)
error_response.raise_exception(response=json_response)

return [
from_dict(data_class=PartialRefund, data=item, config=DACITE_CONFIG)
for item in json_response
Expand Down
87 changes: 87 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from decimal import Decimal
from unittest.mock import Mock, patch

import pytest
Expand Down Expand Up @@ -103,6 +104,43 @@ def mock_order_unauthorized_error_response():
}


@pytest.fixture
def mock_refund_error_response():
return {
"errors": [
{
"code": "BAR-7010",
"title": "Refund Error",
"description": "Não foi possível realizar o reembolso",
}
],
"metadata": {
"totalRecords": 1,
"totalPages": 1,
"requestDatetime": "2025-04-15T10:34:29.576147084-03:00[America/Sao_Paulo]",
},
}


@pytest.fixture
def mock_refund_error_response_with_charge_uuid():
return {
"errors": [
{
"code": "BAR-7010",
"title": "Refund Error",
"description": "Não foi possível realizar o reembolso",
"additionalInfo": {"chargeUUID": "abc123-charge-uuid"},
}
],
"metadata": {
"totalRecords": 1,
"totalPages": 1,
"requestDatetime": "2025-04-15T10:34:29.576147084-03:00[America/Sao_Paulo]",
},
}


@pytest.fixture
def mock_charge_response():
return {
Expand Down Expand Up @@ -704,3 +742,52 @@ def test_create_buyer_with_api_version(
f"{barte_client.base_url}/v2/buyers",
f"{barte_client.base_url}/v1/buyers",
]

@patch("barte.client.requests.Session.request")
def test_refund_charge_with_error(
self, mock_request, barte_client, mock_refund_error_response
):
"""Test refund charge returns BarteError on API error"""
mock_request.return_value.json.return_value = mock_refund_error_response
mock_request.return_value.raise_for_status = Mock()

with pytest.raises(BarteError) as exc_info:
barte_client.refund_charge("d54f6553-8bcf-4376-a995-aaffb6d29492")

assert exc_info.value.code == "BAR-7010"
assert exc_info.value.message == "Não foi possível realizar o reembolso"
assert exc_info.value.charge_uuid is None

@patch("barte.client.requests.Session.request")
def test_partial_refund_charge_with_error(
self, mock_request, barte_client, mock_refund_error_response
):
"""Test partial refund charge returns BarteError on API error"""
mock_request.return_value.json.return_value = mock_refund_error_response
mock_request.return_value.raise_for_status = Mock()

with pytest.raises(BarteError) as exc_info:
barte_client.partial_refund_charge(
"d54f6553-8bcf-4376-a995-aaffb6d29492", value=Decimal("10.00")
)

assert exc_info.value.code == "BAR-7010"
assert exc_info.value.message == "Não foi possível realizar o reembolso"
assert exc_info.value.charge_uuid is None

@patch("barte.client.requests.Session.request")
def test_refund_charge_with_error_and_charge_uuid(
self, mock_request, barte_client, mock_refund_error_response_with_charge_uuid
):
"""Test refund charge returns BarteError with charge_uuid when provided"""
mock_request.return_value.json.return_value = (
mock_refund_error_response_with_charge_uuid
)
mock_request.return_value.raise_for_status = Mock()

with pytest.raises(BarteError) as exc_info:
barte_client.refund_charge("d54f6553-8bcf-4376-a995-aaffb6d29492")

assert exc_info.value.code == "BAR-7010"
assert exc_info.value.message == "Não foi possível realizar o reembolso"
assert exc_info.value.charge_uuid == "abc123-charge-uuid"