016 add creating order to adapter

This commit is contained in:
Раис Юсупалиев
2026-03-14 03:54:55 +03:00
parent 66beab4682
commit 15a17be4ed
12 changed files with 607 additions and 12 deletions
+48 -7
View File
@@ -16,6 +16,7 @@
## Продуктовые требования
- Принимать запрос на расчёт стоимости доставки (откуда, куда, вес, габариты)
- Принимать запрос на создание заказа CDEK по контракту из `http-client.http` для сценария "доставка, до двери"
- Опрашивать всех зарегистрированных провайдеров параллельно
- Возвращать унифицированный список тарифов, отсортированных по цене
- Если провайдер вернул ошибку или не ответил вовремя — исключить его из результата, не падая целиком
@@ -29,7 +30,7 @@
### Фаза 1
- **CDEK** — https://apidoc.cdek.ru/
- Аутентификация: OAuth2 (client credentials)
- Операции: расчёт тарифа
- Операции: расчёт тарифа, регистрация заказа
- Cache TTL: 15 минут
### Фаза 2+
@@ -41,16 +42,19 @@
### Controller (`app/controllers/v1/delivery.py`)
- `POST /api/v1/delivery/price` — принимает `DeliveryRequest`, возвращает `list[DeliveryPrice]`
- `POST /api/v1/delivery/order` — принимает `OrderCreateRequest`, возвращает `OrderCreateResponse`
- Парсинг и валидация входных данных через Pydantic
- Маппинг исключений сервиса в HTTP-ответы
- Вызывает ровно один метод Service: `AggregatorService.get_all_prices()`
- Каждый endpoint вызывает ровно один метод Service: `AggregatorService.get_all_prices()` или `AggregatorService.create_order()`
### Service (`app/services/aggregator.py`)
- `AggregatorService.get_all_prices(request: DeliveryRequest) -> list[DeliveryPrice]`
- Распределяет запросы по всем зарегистрированным провайдерам через `asyncio.gather(..., return_exceptions=True)`
- Фильтрует упавшие результаты
- Сортирует тарифы по цене
- Не содержит бизнес-логики и логики, специфичной для провайдеров
- `AggregatorService.create_order(request: OrderCreateRequest) -> OrderCreateResponse`
- `AggregatorService.create_order()` оркестрирует регистрацию заказа в CDEK через injected adapter dependency
- Service не содержит бизнес-логики и provider HTTP-деталей
### Business Logic (`app/domain/`)
- Правила сортировки и фильтрации тарифов
@@ -75,7 +79,10 @@
- `cdek/client.py` — HTTP-клиент (httpx AsyncClient), аутентификация, ретраи, таймаут (10с)
- `cdek/auth.py` — управление OAuth2-токеном
- `cdek/mapper.py` — ответ CDEK → `DeliveryPrice`
- Каждый адаптер владеет своей конфигурацией; наружу экспонирует только `get_price()`
- `cdek/order_mapper.py` — request/response mapping для регистрации заказа CDEK
- Каждый адаптер владеет своей конфигурацией; наружу экспонирует только service-facing methods, необходимые соответствующему use-case
Для сценария создания заказа CDEK adapter принимает валидированную order model, отправляет контракт `Регистрация заказа (тип "доставка", до двери)` из `http-client.http` и возвращает внутреннюю response model без утечки HTTP-деталей в Service.
---
@@ -102,6 +109,38 @@ delivery_days_min: int
delivery_days_max: int
```
### Входная: `OrderCreateRequest`
```
type: Literal[2]
tariff_code: Literal[136]
comment: str | None
sender:
company: str | None
name: str
email: str
phones: list[{number: str}]
recipient:
name: str
email: str
phones: list[{number: str}]
from_location:
address: str
city: str
country_code: str
to_location:
address: str
city: str
country_code: str
services: list[{code: str, parameter: str}]
packages: list[{number: str, weight: int, length: int, width: int, height: int, comment: str | None}]
```
### Выходная: `OrderCreateResponse`
```
provider: str
order_uuid: str
```
---
## Технологический стек
@@ -126,7 +165,7 @@ app/
│ └── v1/
│ └── delivery.py # Controller
├── services/
│ └── aggregator.py # Service
│ └── aggregator.py # Service
├── domain/
│ └── price.py # Business Logic
├── adapters/
@@ -135,13 +174,15 @@ app/
│ └── cdek/
│ ├── client.py
│ ├── auth.py
── mapper.py
── mapper.py
│ └── order_mapper.py
├── repositories/
│ └── cache/
│ └── redis_cache.py # Repository
├── schemas/
│ ├── request.py
── response.py
── response.py
│ └── order.py
└── config.py
```