New tasks
This commit is contained in:
@@ -166,6 +166,7 @@ class CDEKClient:
|
|||||||
country_code=request.country_code,
|
country_code=request.country_code,
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
|
"type": 2,
|
||||||
"from_location": {"code": from_city_code},
|
"from_location": {"code": from_city_code},
|
||||||
"to_location": {"code": to_city_code},
|
"to_location": {"code": to_city_code},
|
||||||
"packages": [
|
"packages": [
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
image: yusupal1ev/g2s-aggregator:0.0.0
|
image: yusupal1ev/g2s-aggregator:0.0.0
|
||||||
container_name: aggregator
|
container_name: g2s-aggregator
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
+5
-4
@@ -1,7 +1,7 @@
|
|||||||
# Spec Tasks Index
|
# Spec Tasks Index
|
||||||
|
|
||||||
> ⚠️ This file is generated. Do not edit manually.
|
> ⚠️ This file is generated. Do not edit manually.
|
||||||
> Generated at (UTC): `2026-03-14T00:57:33+00:00`
|
> Generated at (UTC): `2026-03-15T20:06:00+00:00`
|
||||||
|
|
||||||
## Tasks
|
## Tasks
|
||||||
|
|
||||||
@@ -24,10 +24,11 @@
|
|||||||
| 014 | DONE | 2026-03-12 | Add minimal structlog JSON logging | `spec/tasks/014_add_minimal_structlog_json_logging.md` |
|
| 014 | DONE | 2026-03-12 | Add minimal structlog JSON logging | `spec/tasks/014_add_minimal_structlog_json_logging.md` |
|
||||||
| 015 | DONE | 2026-03-13 | Add minimal OpenTelemetry tracing | `spec/tasks/015_add_minimal_opentelemetry_tracing.md` |
|
| 015 | DONE | 2026-03-13 | Add minimal OpenTelemetry tracing | `spec/tasks/015_add_minimal_opentelemetry_tracing.md` |
|
||||||
| 016 | DONE | 2026-03-14 | Add CDEK order registration adapter | `spec/tasks/016_add_cdek_order_registration_adapter.md` |
|
| 016 | DONE | 2026-03-14 | Add CDEK order registration adapter | `spec/tasks/016_add_cdek_order_registration_adapter.md` |
|
||||||
| 017 | TODO | 2026-03-14 | Add CDEK order creation endpoint | `spec/tasks/017_add_cdek_order_creation_endpoint.md` |
|
| 017 | TODO | 2026-03-14 | Return all tariffs from CDEK price calculation | `spec/tasks/017_return_all_cdek_tariffs.md` |
|
||||||
|
| 018 | TODO | 2026-03-14 | Add CDEK order creation endpoint | `spec/tasks/018_add_cdek_order_creation_endpoint.md` |
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
- Total: **18**
|
- Total: **19**
|
||||||
- TODO: **1**
|
- TODO: **2**
|
||||||
- DONE: **17**
|
- DONE: **17**
|
||||||
|
|||||||
+3
-2
@@ -50,6 +50,7 @@
|
|||||||
### Service (`app/services/aggregator.py`)
|
### Service (`app/services/aggregator.py`)
|
||||||
- `AggregatorService.get_all_prices(request: DeliveryRequest) -> list[DeliveryPrice]`
|
- `AggregatorService.get_all_prices(request: DeliveryRequest) -> list[DeliveryPrice]`
|
||||||
- Распределяет запросы по всем зарегистрированным провайдерам через `asyncio.gather(..., return_exceptions=True)`
|
- Распределяет запросы по всем зарегистрированным провайдерам через `asyncio.gather(..., return_exceptions=True)`
|
||||||
|
- Принимает от каждого провайдера список тарифов и объединяет их в единый список
|
||||||
- Фильтрует упавшие результаты
|
- Фильтрует упавшие результаты
|
||||||
- Сортирует тарифы по цене
|
- Сортирует тарифы по цене
|
||||||
- `AggregatorService.create_order(request: OrderCreateRequest) -> OrderCreateResponse`
|
- `AggregatorService.create_order(request: OrderCreateRequest) -> OrderCreateResponse`
|
||||||
@@ -74,11 +75,11 @@
|
|||||||
```python
|
```python
|
||||||
class DeliveryProvider(ABC):
|
class DeliveryProvider(ABC):
|
||||||
name: str
|
name: str
|
||||||
async def get_price(self, request: DeliveryRequest) -> DeliveryPrice: ...
|
async def get_prices(self, request: DeliveryRequest) -> list[DeliveryPrice]: ...
|
||||||
```
|
```
|
||||||
- `cdek/client.py` — HTTP-клиент (httpx AsyncClient), аутентификация, ретраи, таймаут (10с)
|
- `cdek/client.py` — HTTP-клиент (httpx AsyncClient), аутентификация, ретраи, таймаут (10с)
|
||||||
- `cdek/auth.py` — управление OAuth2-токеном
|
- `cdek/auth.py` — управление OAuth2-токеном
|
||||||
- `cdek/mapper.py` — ответ CDEK → `DeliveryPrice`
|
- `cdek/mapper.py` — ответ CDEK → `list[DeliveryPrice]`
|
||||||
- `cdek/order_mapper.py` — request/response mapping для регистрации заказа CDEK
|
- `cdek/order_mapper.py` — request/response mapping для регистрации заказа CDEK
|
||||||
- Каждый адаптер владеет своей конфигурацией; наружу экспонирует только service-facing methods, необходимые соответствующему use-case
|
- Каждый адаптер владеет своей конфигурацией; наружу экспонирует только service-facing methods, необходимые соответствующему use-case
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
id: 017
|
||||||
|
title: Return all tariffs from CDEK price calculation
|
||||||
|
status: TODO
|
||||||
|
created: 2026-03-14
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context
|
||||||
|
Сейчас `POST /api/v1/delivery/price` для CDEK возвращает только один тариф, хотя продуктовый контракт требует возвращать унифицированный список тарифов. Текущая реализация adapter/service использует однокотировочный provider contract и CDEK mapper берёт только первый элемент `tariff_codes[0]`.
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Изменить price flow так, чтобы CDEK adapter возвращал все тарифы из успешного ответа CDEK, а service агрегировал и сортировал объединённый список тарифов без изменения архитектурных границ слоёв.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
- Scope задачи ограничен расчётом стоимости доставки и CDEK tariff list response; не изменять order creation flow.
|
||||||
|
- Controller должен сохранить текущий публичный endpoint `POST /api/v1/delivery/price` и по-прежнему вызывать ровно один метод Service.
|
||||||
|
- Service остаётся orchestration layer: собирает тарифы от провайдеров, работает с cache и делегирует фильтрацию/сортировку в Business Logic.
|
||||||
|
- Pure business rules не переносить в Service или Adapter.
|
||||||
|
- Изменение должно затронуть provider contract так, чтобы один provider мог вернуть несколько тарифов в одном запросе.
|
||||||
|
- Scope задачи не включает добавление новых провайдеров, новых endpoint'ов и расширение response schema beyond текущего `DeliveryPrice`, если это не требуется для возврата всех тарифов.
|
||||||
|
- Не изменять файлы в `spec/`.
|
||||||
|
|
||||||
|
## Acceptance criteria
|
||||||
|
- Интерфейс `DeliveryProvider` поддерживает возврат списка тарифов для одного provider request.
|
||||||
|
- CDEK mapper преобразует все элементы `tariff_codes` из валидного ответа CDEK в список `DeliveryPrice`, а не только первый тариф.
|
||||||
|
- CDEK provider adapter возвращает service полный список тарифов, полученный из ответа CDEK.
|
||||||
|
- `AggregatorService.get_all_prices()` корректно обрабатывает список тарифов от каждого provider, объединяет их в единый список и передаёт его в domain filtering/sorting.
|
||||||
|
- Cache coordination в service поддерживает сохранение и чтение списка тарифов для provider request.
|
||||||
|
- `POST /api/v1/delivery/price` возвращает все тарифы CDEK в унифицированном формате, отсортированные по цене по возрастанию.
|
||||||
|
- Existing graceful degradation сохраняется: failure одного provider исключает только его тарифы и не ломает успешные результаты других providers.
|
||||||
|
|
||||||
|
## Definition of Done
|
||||||
|
- [ ] Обновлён provider contract для возврата списка тарифов.
|
||||||
|
- [ ] Обновлены CDEK mapper и adapter/client для многотарифного ответа.
|
||||||
|
- [ ] Обновлён `AggregatorService.get_all_prices()` для объединения и кеширования списков тарифов.
|
||||||
|
- [ ] Добавлены или обновлены tests для adapter, service и controller/API сценариев многотарифного ответа.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
- Обновить `tests/adapters/delivery_providers/cdek/test_mapper.py` для проверки mapping всех тарифов из `tariff_codes`.
|
||||||
|
- Обновить `tests/adapters/delivery_providers/cdek/test_client.py` для проверки, что provider возвращает список тарифов, а не один объект.
|
||||||
|
- Обновить `tests/services/test_aggregator.py` для flattening provider results, cache hit/miss со списком тарифов и partial failure сценариев.
|
||||||
|
- Обновить `tests/controllers/v1/test_delivery.py` для проверки, что API возвращает несколько тарифов CDEK в одном ответе.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
- `poetry run pytest tests/adapters/delivery_providers/cdek/test_mapper.py -q`
|
||||||
|
- `poetry run pytest tests/adapters/delivery_providers/cdek/test_client.py -q`
|
||||||
|
- `poetry run pytest tests/services/test_aggregator.py -q`
|
||||||
|
- `poetry run pytest tests/controllers/v1/test_delivery.py -q`
|
||||||
|
- `python3 spec/gen_spec_index.py --check`
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
id: 017
|
id: 018
|
||||||
title: Add CDEK order creation endpoint
|
title: Add CDEK order creation endpoint
|
||||||
status: TODO
|
status: TODO
|
||||||
created: 2026-03-14
|
created: 2026-03-14
|
||||||
Reference in New Issue
Block a user