BR 1.17 — Catalog Service

Статус: not_started

Задачи

1. Pre-flight аудит (30 мин)

  • SQL-запрос на test+prod БД: найти продукты с >1 structural-модами
    SELECT product_id, COUNT(*) FROM product_modifiers
    WHERE binding_type = 'structural'
    GROUP BY product_id HAVING COUNT(*) > 1;
  • Проверить paykeeper-adapter/.../CatalogEventConsumer.java — какое поле используется для маппинга PK ↔ ERP (sku / product_id / отдельная таблица)
  • Решить путь: добавить products.sku_1c отдельным полем, или оставить sku с префиксом 1c: (если PK не конфликтует)

2. Liquibase миграция 031-br-1-17-modifier-options-sku-1c.xml

  • ALTER TABLE modifier_options ADD COLUMN sku_1c VARCHAR(50)
  • ALTER TABLE modifier_options ADD COLUMN deleted_at TIMESTAMP (если не было)
  • CREATE INDEX idx_modifier_options_sku_1c ON modifier_options (sku_1c) WHERE sku_1c IS NOT NULL
  • CREATE UNIQUE INDEX uq_modifier_options_group_sku_1c ON modifier_options (modifier_group_id, sku_1c) WHERE sku_1c IS NOT NULL AND deleted_at IS NULL

3. Entity / DTO

  • ModifierOption.java — поля skuOneC (column sku_1c) + deletedAt
  • ModifierOptionRequest.java / ModifierOptionResponse.java — поле sku_1c с @JsonProperty("sku_1c")
  • ModifierGroupResponse.options[] — sku_1c в каждой опции

4. Service-валидация

  • ModifierGroupService.updateGroup() — при PATCH опции в structural-привязке требовать sku_1c
  • ProductModifierService.attach() — при binding_type='structural' проверить sku_1c всех опций группы
  • ProductModifierService.updateBinding() — при смене на structural тот же чек
  • Обработка DataIntegrityViolationException от unique index → бросать DUPLICATE_SKU_1C_IN_GROUP

5. Контроллер — error mapping

  • STRUCTURAL_OPTION_MISSING_SKU_1C → HTTP 422 (UNPROCESSABLE_ENTITY)
  • DUPLICATE_SKU_1C_IN_GROUP → HTTP 422

6. Kafka event

  • CatalogEventPublisher.publishModifierGroupUpserted() — добавить sku_1c в payload каждой опции

7. Soft-delete опций

  • ModifierOptionRepository.findActiveByGroupId() — только deleted_at IS NULL
  • ModifierOptionService.delete() — выставлять deleted_at = now() вместо физического DELETE
  • Lookup по ID должен возвращать запись даже с deleted_at (для исторических заказов)

8. Тесты

  • ModifierGroupServiceTest — валидация sku_1c обязателен при structural
  • ModifierGroupServiceTest — дубликат sku_1c в группе → ошибка
  • ModifierOptionRepositoryTest — soft-delete: deleted_at заполнен, запись остаётся в БД, не возвращается в findActive

9. Smoke verification

  • POST модификатор-группы с opt {name=300, sku_1c=‘001’}, opt {name=400, sku_1c=‘002’} → 201 OK, sku_1c в response
  • PATCH опции, обнулить sku_1c, если группа structural у какого-то товара → 422 STRUCTURAL_OPTION_MISSING_SKU_1C
  • POST 2 опций с одинаковым sku_1c в группу → 422 DUPLICATE_SKU_1C_IN_GROUP
  • DELETE опции → проверка в БД: deleted_at заполнен

Зависимости

  • ModifierOptionRepository, ModifierGroupRepository, ProductModifierRepository
  • CatalogEventPublisher (Kafka)

Ссылки