Добавлено сохранение заказов в postgres

This commit is contained in:
Раис Юсупалиев
2026-04-18 00:33:45 +03:00
parent 2b201a08be
commit bddac60965
38 changed files with 971 additions and 17 deletions
+66
View File
@@ -4,9 +4,12 @@ import asyncio
import hashlib
import json
from collections.abc import Iterable, Mapping, Sequence
from contextlib import AbstractAsyncContextManager
from decimal import Decimal
from typing import Protocol
import structlog
from app.adapters.address_suggestions.base import (
AddressSuggestionClientError,
AddressSuggestionProvider,
@@ -24,10 +27,13 @@ from app.domain.price import (
filter_and_sort_prices,
normalize_delivery_request,
)
from app.repositories.order import OrderData
from app.schemas.payment import InitPaymentRequest, InitPaymentResponse
from app.schemas.request import AddressSuggestRequest, DeliveryCalculationRequest
from app.schemas.response import AddressSuggestion, DeliveryPrice
logger = structlog.get_logger(__name__)
class AggregatorServiceError(RuntimeError):
"""Base exception for AggregatorService failures."""
@@ -67,6 +73,12 @@ class PaymentAdapterProtocol(Protocol):
async def create_payment_link(self, order_uuid: str, amount_kopecks: int) -> str: ...
class OrderRepositoryProtocol(Protocol):
def session(self) -> AbstractAsyncContextManager[object]: ...
async def create_order(self, session: object, order_data: OrderData) -> object: ...
class FilterAndSortPricesFn(Protocol):
def __call__(
self,
@@ -83,6 +95,7 @@ class AggregatorService:
providers: Sequence[DeliveryProvider],
cache: PriceCacheProtocol | None = None,
payment_adapter: PaymentAdapterProtocol | None = None,
order_repository: OrderRepositoryProtocol | None = None,
address_suggestion_providers: Sequence[AddressSuggestionProvider] = (),
address_suggestion_country_to_provider: Mapping[str, str] | None = None,
*,
@@ -93,6 +106,7 @@ class AggregatorService:
self._providers = tuple(providers)
self._cache = cache
self._payment_adapter = payment_adapter
self._order_repository = order_repository
self._weight_round_scale = weight_round_scale
self._provider_price_multiplier = provider_price_multiplier
self._filter_and_sort_prices = filter_and_sort_prices_fn
@@ -180,6 +194,14 @@ class AggregatorService:
amount_kopecks=request.price,
)
except TBankPaymentRequestError as exc:
logger.exception(
"payment_init_rejected",
order_uuid=request.order_uuid,
provider_status_code=exc.status_code,
provider_error_code=exc.error_code,
provider_error_message=exc.provider_message,
provider_error_details=exc.details,
)
raise InvalidInitPaymentRequestError(
"Payment init request is invalid for the configured provider."
) from exc
@@ -192,8 +214,52 @@ class AggregatorService:
"Payment initialization is temporarily unavailable."
) from exc
await self._persist_order(request=request, payment_url=payment_url)
return InitPaymentResponse(payment_url=payment_url)
async def _persist_order(
self,
*,
request: InitPaymentRequest,
payment_url: str,
) -> None:
if self._order_repository is None:
return
try:
async with self._order_repository.session() as session:
await self._order_repository.create_order(
session,
self._to_order_data(request=request, payment_url=payment_url),
)
except Exception:
logger.exception(
"order_persistence_failed",
order_uuid=request.order_uuid,
)
@staticmethod
def _to_order_data(
*,
request: InitPaymentRequest,
payment_url: str,
) -> OrderData:
payload = request.model_dump(mode="json")
return OrderData(
order_uuid=request.order_uuid,
payment_url=payment_url,
price=request.price,
delivery_type=request.type,
tariff_code=request.tariff_code,
sender=payload["sender"],
recipient=payload["recipient"],
from_location=payload["from_location"],
to_location=payload["to_location"],
packages=payload["packages"],
services=payload["services"],
comment=request.comment,
)
async def _get_provider_prices(
self,
*,