Order Service — BR 5.1
Контракты
- Data Model —
expected_ready_at+ 3 поля per-item KDS- API — 3 новых endpoint
- Events — событие
order.item.kitchen_status_changed- Бизнес-логика: Заказы §«KDS-flow позиций»
Что делаем
Миграция Liquibase
-
src/main/resources/db/changelog/0XX_add_kds_fields.xml:- ALTER TABLE
ordersADD COLUMNexpected_ready_attimestamp NULL - ALTER TABLE
order_itemsADD COLUMNkitchen_statusvarchar(20) NOT NULL DEFAULT ‘pending’ - ALTER TABLE
order_itemsADD COLUMNkitchen_started_attimestamp NULL - ALTER TABLE
order_itemsADD COLUMNkitchen_ready_attimestamp NULL - CHECK CONSTRAINT
kitchen_status IN ('pending','preparing','ready') - CREATE INDEX
idx_order_items_kitchen_statusONorder_items (order_id, kitchen_status) - Backfill для legacy:
UPDATE order_items SET kitchen_status='ready' WHERE order_id IN (SELECT id FROM orders WHERE status IN ('ready','closed','delivered','handed_over','in_delivery')) - Регистрация в
db.changelog-master.xml
- ALTER TABLE
Entities
-
Order— добавить полеexpectedReadyAt(LocalDateTime) -
OrderItem— добавить поляkitchenStatus(enum/varchar),kitchenStartedAt,kitchenReadyAt -
KitchenStatusenum:PENDING,PREPARING,READY
Repositories
-
OrderItemRepository:int countByOrderIdAndKitchenStatus(UUID orderId, KitchenStatus status)— для авто-переходаList<OrderItem> findAllByOrderIdAndKitchenStationId(UUID orderId, UUID stationId)— для batch endpoint
Services
-
OrderService.startCooking(...)— расширить:- Проставлять
expected_ready_at = accepted_at + 15 минут(P0 заглушка; P1 —+ avg(items.assembly_time_seconds)) - Все
order_items.kitchen_statusостаютсяpending(default)
- Проставлять
-
Новый метод
OrderService.updateItemKitchenStatus(orderId, itemId, newStatus, userId):- Найти item, проверить multi-tenancy (
item.order.franchise_id == jwt.franchise_id) - Проверить статус заказа =
accepted(иначеORDER_NOT_IN_KITCHEN_FLOW) - Проверить что переход не назад (
KITCHEN_STATUS_BACKWARD) - Обновить статус, проставить
kitchen_started_at/kitchen_ready_at - Опубликовать событие
order.item.kitchen_status_changed - Auto-transition check: если все items заказа
kitchen_status=ready→ перевестиorders.status=ready,ready_at=NOW(), опубликоватьorder.readyсtrigger=kds_auto - Транзакция
- Найти item, проверить multi-tenancy (
-
Новый метод
OrderService.markStationReady(orderId, stationId, userId):- Найти все items с
kitchen_station_id = stationId AND kitchen_status != 'ready' - Если 0 — это идемпотентный success (no-op)
- Если есть items в
pendingилиpreparing— вернутьSTATION_NOT_READY(требуем сначала индивидуальныеready) - В P0 — простой
PATCHкаждый item наreadyчерезupdateItemKitchenStatus(publishes event per item) - Транзакция
- Найти все items с
-
Новый метод
OrderService.findActiveForKds(franchiseId, storeId, stationIds, status):- Запрос с фильтром по
franchise_id + store_id + status+ JOIN order_items WHEREkitchen_station_id IN stationIds - Загрузить все items заказов (для контекста серых блоков)
- Сформировать DTO с
kitchen_station_name(из cross-service lookup в Catalog Service)
- Запрос с фильтром по
Controllers
-
InternalOrderController:GET /internal/orders/active-by-stations— для pos-bff. X-Service-Token auth, query:franchise_id,store_id,station_ids(csv),status(defaultaccepted)
-
OrderController(или новыйKdsOrderController):PATCH /orders/{id}/items/{itemId}/kitchen-status— JWT с permissionkds.accessPATCH /orders/{id}/kitchen-status?station_id=...— JWT сkds.access
KafkaPublisher
-
OrderEventPublisher:publishItemKitchenStatusChanged(...)— топикorder.item.kitchen_status_changed, ключorder_id- Расширить
publishOrderReady(...)— добавить полеtrigger: "manual" | "kds_auto"в payload
Tests
- Unit:
OrderServiceTest.startCooking_setsExpectedReadyAtOrderServiceTest.updateItemKitchenStatus_blocksBackwardTransitionOrderServiceTest.updateItemKitchenStatus_publishesEventOrderServiceTest.updateItemKitchenStatus_autoTransitionsOrderToReadyOrderServiceTest.markStationReady_idempotentOrderServiceTest.markStationReady_failsOnPendingItems
- Integration:
KdsOrderControllerIntegrationTest— full flow с реальной БД и Kafka в Testcontainers
Конфигурация
-
application.yml:app.kds.default-prep-time-minutes: 15— для расчётаexpected_ready_atв P0
Permission на endpoints
kds.accessобязателен для:PATCH /orders/{id}/items/{itemId}/kitchen-statusPATCH /orders/{id}/kitchen-status
Проверка через стандартный Spring Security. Если permission нет → 403 KDS_ACCESS_DENIED.
Что НЕ делаем
- Не трогаем существующие endpoints (
/start-cooking,/mark-readyи т.д.) — они работают как раньше - Не реализуем
expected_ready_atчерезavg(assembly_time_seconds)— это P1 в BR 5.X - Не подписываемся на новые Kafka события (Order Service — только publisher)
Зависимости от других сервисов
- ❌
kitchen_station_nameдля DTO — берётся через прямой http-вызов Catalog Service (GET /kitchen-stationsс кэшем 5 мин), либо через Kafka snapshot в локальную таблицуkitchen_stations_cache(если решим избежать sync HTTP). В P0 — sync HTTP с Caffeine cache.