020 update city code resolving
This commit is contained in:
+18
-8
@@ -15,7 +15,7 @@
|
||||
|
||||
## Продуктовые требования
|
||||
|
||||
- Принимать запрос на расчёт стоимости доставки (откуда, куда, вес, габариты)
|
||||
- Принимать запрос на расчёт стоимости доставки (идентификаторы городов отправления/назначения, вес, габариты)
|
||||
- Поддерживать необязательный параметр `parcel_type` в запросе расчёта стоимости доставки для фильтрации тарифов по типу отправления
|
||||
- Принимать запрос на создание заказа CDEK по контракту из `http-client.http` для сценария "доставка, до двери"
|
||||
- Опрашивать всех зарегистрированных провайдеров параллельно
|
||||
@@ -23,6 +23,7 @@
|
||||
- Если провайдер вернул ошибку или не ответил вовремя — исключить его из результата, не падая целиком
|
||||
- Кешировать ответы провайдеров для исключения повторных внешних запросов. Время кэширования вынести в конфиг
|
||||
- Применять к цене, полученной от провайдера, конфигурируемый мультипликатор и округлять итоговую цену до целого значения
|
||||
- Для расчёта стоимости использовать локальный справочник `cities_map` с provider-specific данными города; для CDEK брать `cdek.code` без обращения к API подсказок городов
|
||||
|
||||
---
|
||||
|
||||
@@ -42,14 +43,14 @@
|
||||
## Компоненты
|
||||
|
||||
### Controller (`app/controllers/v1/delivery.py`)
|
||||
- `POST /api/v1/delivery/price` — принимает `DeliveryRequest`, возвращает `list[DeliveryPrice]`
|
||||
- `POST /api/v1/delivery/price` — принимает `DeliveryCalculationRequest`, возвращает `list[DeliveryPrice]`
|
||||
- `POST /api/v1/delivery/order` — принимает `OrderCreateRequest`, возвращает `OrderCreateResponse`
|
||||
- Парсинг и валидация входных данных через Pydantic
|
||||
- Маппинг исключений сервиса в HTTP-ответы
|
||||
- Каждый endpoint вызывает ровно один метод Service: `AggregatorService.get_all_prices()` или `AggregatorService.create_order()`
|
||||
|
||||
### Service (`app/services/aggregator.py`)
|
||||
- `AggregatorService.get_all_prices(request: DeliveryRequest) -> list[DeliveryPrice]`
|
||||
- `AggregatorService.get_all_prices(request: DeliveryCalculationRequest) -> list[DeliveryPrice]`
|
||||
- Распределяет запросы по всем зарегистрированным провайдерам через `asyncio.gather(..., return_exceptions=True)`
|
||||
- Принимает от каждого провайдера список тарифов и объединяет их в единый список
|
||||
- Фильтрует упавшие результаты
|
||||
@@ -64,7 +65,7 @@
|
||||
- Логика сравнения цен
|
||||
- Правила применения конфигурируемого мультипликатора к ценам провайдеров
|
||||
- Округление цены после применения мультипликатора до целого значения по детерминированному правилу
|
||||
- Нормализация входных данных (например, правила округления веса)
|
||||
- Нормализация входных данных (например, идентификаторов городов и правил округления веса)
|
||||
- Чистые функции, без IO, без зависимостей от фреймворков
|
||||
|
||||
### Repository (`app/repositories/cache/`)
|
||||
@@ -77,25 +78,34 @@
|
||||
```python
|
||||
class DeliveryProvider(ABC):
|
||||
name: str
|
||||
async def get_prices(self, request: DeliveryRequest) -> list[DeliveryPrice]: ...
|
||||
async def get_prices(self, request: DeliveryCalculationRequest) -> list[DeliveryPrice]: ...
|
||||
```
|
||||
- `cdek/client.py` — HTTP-клиент (httpx AsyncClient), аутентификация, ретраи, таймаут (10с)
|
||||
- `cdek/auth.py` — управление OAuth2-токеном
|
||||
- `cdek/mapper.py` — ответ CDEK → `list[DeliveryPrice]`
|
||||
- `cdek/order_mapper.py` — request/response mapping для регистрации заказа CDEK
|
||||
- Каждый адаптер владеет своей конфигурацией; наружу экспонирует только service-facing methods, необходимые соответствующему use-case
|
||||
- Для расчёта тарифа CDEK adapter принимает city identifiers из `DeliveryCalculationRequest`, находит запись в `cities_map`, берёт `cdek.code` и передаёт его в CDEK API
|
||||
|
||||
Для сценария создания заказа CDEK adapter принимает валидированную order model, отправляет контракт `Регистрация заказа (тип "доставка", до двери)` из `http-client.http` и возвращает внутреннюю response model без утечки HTTP-деталей в Service.
|
||||
|
||||
---
|
||||
|
||||
## Reference Data
|
||||
|
||||
- `cities_map` содержит city identifier и provider-specific данные города для price flow.
|
||||
- Справочник может быть частично заполнен; отсутствие provider-specific данных для города должно обрабатываться детерминированно.
|
||||
- Структура справочника должна допускать появление дополнительных провайдеров без изменения публичного API расчёта.
|
||||
|
||||
---
|
||||
|
||||
## Модели данных
|
||||
|
||||
### Входная: `DeliveryRequest`
|
||||
### Входная: `DeliveryCalculationRequest`
|
||||
```
|
||||
entity: Enum(individual, legal)
|
||||
from_city: str
|
||||
to_city: str
|
||||
from_city: int
|
||||
to_city: int
|
||||
weight_kg: float
|
||||
length_cm: float
|
||||
width_cm: float
|
||||
|
||||
Reference in New Issue
Block a user