016 add creating order to adapter
This commit is contained in:
+6
-4
@@ -1,7 +1,7 @@
|
||||
# Spec Tasks Index
|
||||
|
||||
> ⚠️ This file is generated. Do not edit manually.
|
||||
> Generated at (UTC): `2026-03-13T14:21:47+00:00`
|
||||
> Generated at (UTC): `2026-03-14T00:55:12+00:00`
|
||||
|
||||
## Tasks
|
||||
|
||||
@@ -22,10 +22,12 @@
|
||||
| 012 | DONE | 2026-03-08 | Remove observability and SigNoz stack for phase 1 | `spec/tasks/012_remove_observability_and_signoz_for_phase1.md` |
|
||||
| 013 | DONE | 2026-03-09 | Add configurable provider price multiplier in domain logic | `spec/tasks/013_add_configurable_provider_price_multiplier.md` |
|
||||
| 014 | DONE | 2026-03-12 | Add minimal structlog JSON logging | `spec/tasks/014_add_minimal_structlog_json_logging.md` |
|
||||
| 015 | TODO | 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` |
|
||||
| 017 | TODO | 2026-03-14 | Add CDEK order creation endpoint | `spec/tasks/017_add_cdek_order_creation_endpoint.md` |
|
||||
|
||||
## Summary
|
||||
|
||||
- Total: **16**
|
||||
- Total: **18**
|
||||
- TODO: **1**
|
||||
- DONE: **15**
|
||||
- DONE: **17**
|
||||
|
||||
+48
-7
@@ -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
|
||||
```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: 015
|
||||
title: Add minimal OpenTelemetry tracing
|
||||
status: TODO
|
||||
status: DONE
|
||||
created: 2026-03-13
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
id: 016
|
||||
title: Add CDEK order registration adapter
|
||||
status: DONE
|
||||
created: 2026-03-14
|
||||
---
|
||||
|
||||
## Context
|
||||
Сейчас CDEK adapter поддерживает только расчёт тарифа. Новый сценарий требует регистрацию заказа в CDEK по контракту из `http-client.http` в разделе `Регистрация заказа (тип "доставка", до двери)`.
|
||||
|
||||
## Goal
|
||||
Расширить существующий CDEK adapter регистрацией заказа: добавить в текущий adapter/provider сбор payload по контракту, вызов `POST /v2/orders`, детерминированную обработку provider errors и маппинг успешного ответа во внутреннюю response model.
|
||||
|
||||
## Constraints
|
||||
- Изменения ограничены существующим Adapter layer и schema/mapper моделями, необходимыми для стабильного adapter contract.
|
||||
- Использовать существующий OAuth2 flow CDEK; не дублировать auth logic.
|
||||
- Контракт запроса должен соответствовать разделу `Регистрация заказа (тип "доставка", до двери)` из `http-client.http`.
|
||||
- В scope этой задачи входят только значения `type=2` и `tariff_code=535`; не расширять поддержку на другие типы заказа и тарифы.
|
||||
- Не добавлять новые controller/service модули, controller routing, service orchestration, cache behavior и business logic.
|
||||
- Не изменять файлы в `spec/`.
|
||||
|
||||
## Acceptance criteria
|
||||
- Существующий CDEK adapter/provider предоставляет стабильный метод регистрации заказа, принимающий валидированную internal model вместо raw dict.
|
||||
- Adapter отправляет `POST /v2/orders` с bearer token и JSON payload, соответствующим контракту из `http-client.http`.
|
||||
- Успешный ответ CDEK маппится во внутреннюю response model с `order_uuid`, полученным из `entity.uuid`.
|
||||
- Provider validation errors класса 4xx маппятся в детерминированную provider request error, а transport/5xx ошибки — в adapter client error.
|
||||
- Adapter tests покрывают success case, payload mapping, response mapping и error handling для order registration.
|
||||
|
||||
## Definition of Done
|
||||
- [ ] Расширен существующий adapter method set для регистрации заказа CDEK.
|
||||
- [ ] Реализованы request/response mapper(s) для order registration.
|
||||
- [ ] Переиспользуется существующий OAuth2 auth client.
|
||||
- [ ] Добавлены adapter tests для order registration сценария.
|
||||
|
||||
## Tests
|
||||
- Добавить `tests/adapters/delivery_providers/cdek/test_order_client.py` для success/error сценариев регистрации заказа.
|
||||
- Проверить, что payload содержит поля из контракта `http-client.http`.
|
||||
- Проверить маппинг `entity.uuid` в внутреннюю response model.
|
||||
- Для внешних HTTP взаимодействий использовать stubs/mocks.
|
||||
|
||||
## Commands
|
||||
- `poetry run pytest tests/adapters/delivery_providers/cdek/test_order_client.py -q`
|
||||
- `python3 spec/gen_spec_index.py --check`
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
id: 017
|
||||
title: Add CDEK order creation endpoint
|
||||
status: TODO
|
||||
created: 2026-03-14
|
||||
---
|
||||
|
||||
## Context
|
||||
Сейчас API поддерживает только `POST /api/v1/delivery/price`. Для нового пользовательского сценария нужен отдельный endpoint `/order`, который создаёт заказ в CDEK по контракту из `http-client.http`.
|
||||
|
||||
## Goal
|
||||
Добавить `POST /api/v1/order` в существующий controller и существующий service с request/response schema и error mapping для регистрации заказа в CDEK через adapter contract из задачи `016`.
|
||||
|
||||
## Constraints
|
||||
- Controller отвечает только за DTO validation, routing и mapping service exceptions в HTTP responses.
|
||||
- Endpoint должен вызывать ровно один метод Service: `AggregatorService.create_order()`.
|
||||
- Новый endpoint должен быть добавлен в существующий controller модуль `app/controllers/v1/delivery.py`; не создавать отдельный controller модуль.
|
||||
- Логика создания заказа должна быть добавлена в существующий service модуль `app/services/aggregator.py`; не создавать отдельный service модуль.
|
||||
- Service оркестрирует только вызов injected CDEK order adapter и не содержит business logic или provider HTTP-деталей.
|
||||
- Контракт входного запроса должен соответствовать разделу `Регистрация заказа (тип "доставка", до двери)` из `http-client.http`.
|
||||
- Scope задачи не включает кеширование, агрегацию тарифов, расчёт стоимости, новые провайдеры и расширение order flow за пределы CDEK.
|
||||
- Не изменять файлы в `spec/`.
|
||||
|
||||
## Acceptance criteria
|
||||
- Существует endpoint `POST /api/v1/order`, принимающий payload по контракту из `http-client.http`.
|
||||
- Реализованы request/response schemas для создания заказа и минимального успешного ответа API.
|
||||
- Endpoint реализован в существующем controller `app/controllers/v1/delivery.py`.
|
||||
- Controller делегирует обработку только в `AggregatorService.create_order()`.
|
||||
- Service вызывает injected adapter для регистрации заказа и возвращает response model с `order_uuid`.
|
||||
- Логика orchestration размещена в существующем service `app/services/aggregator.py`.
|
||||
- Ошибки валидации входного payload возвращают 422, provider request errors маппятся в 400, недоступность CDEK и transport failures — в 503.
|
||||
- API и service tests покрывают success case и основные failure scenarios.
|
||||
|
||||
## Definition of Done
|
||||
- [ ] Добавлены order request/response schemas.
|
||||
- [ ] Реализован метод `AggregatorService.create_order()` для оркестрации регистрации заказа.
|
||||
- [ ] Реализован endpoint `POST /api/v1/order` в существующем controller.
|
||||
- [ ] Добавлены service и controller/API tests для order creation flow.
|
||||
|
||||
## Tests
|
||||
- Добавить `tests/services/test_order.py` для проверки вызова adapter и маппинга ошибок сервиса.
|
||||
- Добавить `tests/controllers/v1/test_order.py` для success case, schema validation и HTTP mapping ошибок.
|
||||
- При необходимости обновить `tests/smoke/test_app_import.py` для проверки подключения нового endpoint и service wiring без новых модулей.
|
||||
- Использовать test doubles для adapter dependency.
|
||||
|
||||
## Commands
|
||||
- `poetry run pytest tests/services/test_order.py -q`
|
||||
- `poetry run pytest tests/controllers/v1/test_order.py -q`
|
||||
- `poetry run pytest tests/smoke/test_app_import.py -q`
|
||||
- `python3 spec/gen_spec_index.py --check`
|
||||
Reference in New Issue
Block a user