From 9b9cca0a7c8342abdf1a4058f85d93b8380e0998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D0=B0=D0=B8=D1=81=20=D0=AE=D1=81=D1=83=D0=BF=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B5=D0=B2?= Date: Sun, 15 Mar 2026 23:06:26 +0300 Subject: [PATCH] New tasks --- .../delivery_providers/cdek/client.py | 1 + docker-compose.yml | 2 +- spec/index.md | 9 ++-- spec/overview.md | 5 +- spec/tasks/017_return_all_cdek_tariffs.md | 49 +++++++++++++++++++ ...> 018_add_cdek_order_creation_endpoint.md} | 2 +- 6 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 spec/tasks/017_return_all_cdek_tariffs.md rename spec/tasks/{017_add_cdek_order_creation_endpoint.md => 018_add_cdek_order_creation_endpoint.md} (99%) diff --git a/app/adapters/delivery_providers/cdek/client.py b/app/adapters/delivery_providers/cdek/client.py index bce0046..4b167d8 100644 --- a/app/adapters/delivery_providers/cdek/client.py +++ b/app/adapters/delivery_providers/cdek/client.py @@ -166,6 +166,7 @@ class CDEKClient: country_code=request.country_code, ) return { + "type": 2, "from_location": {"code": from_city_code}, "to_location": {"code": to_city_code}, "packages": [ diff --git a/docker-compose.yml b/docker-compose.yml index 503d857..6bb3d29 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: app: image: yusupal1ev/g2s-aggregator:0.0.0 - container_name: aggregator + container_name: g2s-aggregator ports: - "8000:8000" depends_on: diff --git a/spec/index.md b/spec/index.md index 8216196..778f0ea 100644 --- a/spec/index.md +++ b/spec/index.md @@ -1,7 +1,7 @@ # Spec Tasks Index > ⚠️ 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 @@ -24,10 +24,11 @@ | 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` | | 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 -- Total: **18** -- TODO: **1** +- Total: **19** +- TODO: **2** - DONE: **17** diff --git a/spec/overview.md b/spec/overview.md index adc79cd..ead467d 100644 --- a/spec/overview.md +++ b/spec/overview.md @@ -50,6 +50,7 @@ ### Service (`app/services/aggregator.py`) - `AggregatorService.get_all_prices(request: DeliveryRequest) -> list[DeliveryPrice]` - Распределяет запросы по всем зарегистрированным провайдерам через `asyncio.gather(..., return_exceptions=True)` +- Принимает от каждого провайдера список тарифов и объединяет их в единый список - Фильтрует упавшие результаты - Сортирует тарифы по цене - `AggregatorService.create_order(request: OrderCreateRequest) -> OrderCreateResponse` @@ -74,11 +75,11 @@ ```python class DeliveryProvider(ABC): 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/auth.py` — управление OAuth2-токеном -- `cdek/mapper.py` — ответ CDEK → `DeliveryPrice` +- `cdek/mapper.py` — ответ CDEK → `list[DeliveryPrice]` - `cdek/order_mapper.py` — request/response mapping для регистрации заказа CDEK - Каждый адаптер владеет своей конфигурацией; наружу экспонирует только service-facing methods, необходимые соответствующему use-case diff --git a/spec/tasks/017_return_all_cdek_tariffs.md b/spec/tasks/017_return_all_cdek_tariffs.md new file mode 100644 index 0000000..48eda5a --- /dev/null +++ b/spec/tasks/017_return_all_cdek_tariffs.md @@ -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` diff --git a/spec/tasks/017_add_cdek_order_creation_endpoint.md b/spec/tasks/018_add_cdek_order_creation_endpoint.md similarity index 99% rename from spec/tasks/017_add_cdek_order_creation_endpoint.md rename to spec/tasks/018_add_cdek_order_creation_endpoint.md index 54ab142..09f18e6 100644 --- a/spec/tasks/017_add_cdek_order_creation_endpoint.md +++ b/spec/tasks/018_add_cdek_order_creation_endpoint.md @@ -1,5 +1,5 @@ --- -id: 017 +id: 018 title: Add CDEK order creation endpoint status: TODO created: 2026-03-14