import sys from pathlib import Path import asyncio import pytest from fastapi import HTTPException, status from requests import RequestException PROJECT_ROOT = Path(__file__).resolve().parents[1] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from pydantic import ValidationError from src.modules.pagamentos.mercadopago_service import ( MercadoPagoService, MercadoPagoTransfer, ) class _FakePaymentClient: def __init__(self, error: Exception) -> None: self._error = error def get(self, payment_id: int): # pragma: no cover - behaviour tested via exception raise self._error class _FakeSDK: def __init__(self, error: Exception) -> None: self._error = error def payment(self): # pragma: no cover - simple passthrough return _FakePaymentClient(self._error) def test_get_payment_translates_request_exception_to_bad_gateway(): service = MercadoPagoService(access_token="token", public_key="public") service.sdk = _FakeSDK(RequestException("proxy error")) # type: ignore[assignment] with pytest.raises(HTTPException) as error_info: asyncio.run(service.get_payment(123)) assert error_info.value.status_code == status.HTTP_502_BAD_GATEWAY assert "Mercado Pago" in error_info.value.detail def test_transfer_accepts_amount_or_percentage(): transfer_amount = MercadoPagoTransfer(collector_id=123, amount=10.0) assert transfer_amount.amount == 10.0 assert transfer_amount.percentage is None transfer_percentage = MercadoPagoTransfer(collector_id=123, percentage=25.0) assert transfer_percentage.percentage == 25.0 assert transfer_percentage.amount is None @pytest.mark.parametrize( "payload", [ {"collector_id": 123}, {"collector_id": 123, "amount": 10.0, "percentage": 10.0}, ], ) def test_transfer_requires_exclusive_amount_or_percentage(payload): with pytest.raises(ValidationError): MercadoPagoTransfer(**payload) def test_prepare_preference_enforces_checkout_pro_payment_methods(): service = MercadoPagoService(access_token="token", public_key="public") preference_payload = { "items": [ { "id": "item-123", "title": "Produto teste", "quantity": 1, "unit_price": 100.0, } ], "payment_methods": { # Tenta bloquear cartão de crédito, mas deve ser ignorado "excluded_payment_types": [ {"id": "ticket"}, {"id": "credit_card"}, ], # Tenta bloquear PIX, mas deve ser ignorado "excluded_payment_methods": [ {"id": "pix"}, {"id": "visa"}, ], "installments": 12, }, } prepared = service._prepare_preference_payload(preference_payload) excluded_types = {ptype["id"] for ptype in prepared["payment_methods"]["excluded_payment_types"]} excluded_methods = {pmethod["id"] for pmethod in prepared["payment_methods"]["excluded_payment_methods"]} assert "ticket" in excluded_types assert "credit_card" not in excluded_types assert "bank_transfer" not in excluded_types # Mantém PIX habilitado assert "pix" not in excluded_methods assert prepared["payment_methods"]["installments"] == 1