Files
g2s-aggregator/tests/services/test_provider_routing.py
T
Раис Юсупалиев 3f7c6dc631
Deploy / deploy (push) Failing after 14m35s
Рефактор
2026-06-26 19:29:11 +03:00

188 lines
5.5 KiB
Python

import asyncio
from dataclasses import dataclass, field
from decimal import Decimal
from typing import Any
from app.schemas.payment import InitPaymentRequest, TBankPaymentNotification
from app.schemas.response import DeliveryPrice
from app.services.aggregator import AggregatorService
from tests.payment_fixtures import make_init_payment_payload, make_init_payment_request
class StubPaymentAdapter:
async def create_payment_link(self, order_uuid: str, amount_kopecks: int) -> str:
return "https://pay.test/payment/1"
def verify_payment_notification(self, notification: TBankPaymentNotification) -> None:
return None
class StubValidationAdapter:
def __init__(self, response: DeliveryPrice | None) -> None:
self._response = response
self.calls: list[InitPaymentRequest] = []
async def get_payment_price(
self, request: InitPaymentRequest
) -> DeliveryPrice | None:
self.calls.append(request)
return self._response
@dataclass
class CSEResult:
order_number: str = "CSE-000123"
class StubCSERegistrationAdapter:
def __init__(self) -> None:
self.calls: list[tuple[InitPaymentRequest, str]] = []
async def register_order(
self, request: InitPaymentRequest, order_uuid: str
) -> CSEResult:
self.calls.append((request, order_uuid))
return CSEResult()
class StubCDEKRegistrationAdapter:
def __init__(self) -> None:
self.calls: list[tuple[InitPaymentRequest, str]] = []
async def register_order(
self, request: InitPaymentRequest, order_uuid: str
) -> object:
self.calls.append((request, order_uuid))
raise AssertionError("CDEK adapter must not be called for a CSE order.")
def _cse_price() -> DeliveryPrice:
return DeliveryPrice.model_construct(
provider="cse",
service_name="CSE tariff",
price=Decimal("1250.00"),
currency="RUB",
delivery_days_min=1,
delivery_days_max=2,
tariff_code="cse-guid",
)
def _cse_request() -> InitPaymentRequest:
return make_init_payment_request(
systemData={
"tariff": {
"provider": "cse",
"serviceName": "CSE tariff",
"price": 125000,
"deliveryDaysMin": 1,
"deliveryDaysMax": 2,
"tariffCode": "cse-guid",
},
"parcelType": "parcel",
"weight": "1.0",
"dimensions": {"length": "10", "width": "10", "height": "10"},
}
)
def test_init_payment_routes_validation_to_tariff_provider() -> None:
cse_validation = StubValidationAdapter(_cse_price())
cdek_validation = StubValidationAdapter(None)
service = AggregatorService(
providers=[],
payment_adapter=StubPaymentAdapter(),
payment_price_validation_adapters={
"cdek": cdek_validation,
"cse": cse_validation,
},
provider_price_multiplier=Decimal("1"),
order_uuid_factory=lambda: "order-uuid-1",
)
asyncio.run(service.init_payment(_cse_request()))
assert len(cse_validation.calls) == 1
assert cdek_validation.calls == []
@dataclass
class StoredOrder:
order_uuid: str = "order-uuid-1"
provider: str = "cse"
payload: dict[str, Any] = field(
default_factory=lambda: _cse_request().model_dump(mode="json", by_alias=True)
)
payment_status: str | None = None
tbank_payment_id: int | None = None
provider_order_id: str | None = None
payment_email_sent_at: object | None = None
account_email: str | None = None
class StubSession:
async def __aenter__(self) -> object:
return object()
async def __aexit__(self, *args: object) -> None:
return None
class StubOrderRepository:
def __init__(self, order: StoredOrder) -> None:
self._order = order
def session(self) -> StubSession:
return StubSession()
async def get_order_by_order_uuid(
self, session: object, order_uuid: str, *, for_update: bool = False
) -> StoredOrder:
return self._order
async def mark_payment_status(
self, session: object, order_uuid: str, status: str, payment_id: int
) -> StoredOrder:
self._order.payment_status = status
self._order.tbank_payment_id = payment_id
return self._order
async def mark_provider_order_registered(
self, session: object, order_uuid: str, provider_order_id: str
) -> StoredOrder:
self._order.provider_order_id = provider_order_id
return self._order
def _notification() -> TBankPaymentNotification:
return TBankPaymentNotification(
TerminalKey="TestTerminal",
OrderId="order-uuid-1",
Success=True,
Status="CONFIRMED",
PaymentId=8347568144,
ErrorCode="0",
Amount=125000,
Token="signed-token",
)
def test_notification_routes_registration_to_order_provider() -> None:
order = StoredOrder()
cse_registration = StubCSERegistrationAdapter()
service = AggregatorService(
providers=[],
payment_adapter=StubPaymentAdapter(),
order_repository=StubOrderRepository(order),
order_registration_adapters={
"cdek": StubCDEKRegistrationAdapter(),
"cse": cse_registration,
},
)
result = asyncio.run(service.handle_tbank_payment_notification(_notification()))
assert result == "OK"
assert len(cse_registration.calls) == 1
assert order.provider_order_id == "CSE-000123"