Catalog · Modifiers
Группы модификаторов и опции. Привязка к товарам. Min/max валидация.
Endpoints
GET /modifier-groups список
GET /modifier-groups/{id} детали (price у options НЕ возвращается)
POST /modifier-groups create (silent no-op для options[].price → F44)
PATCH /modifier-groups/{id} update
DELETE /modifier-groups/{id} 204 (НЕ чистит modifier_items в price-list → F45)
POST /catalog/products/{id}/modifiers привязать группу к товару
body: {modifier_group_id, binding_type:"free"|"structural", override_min_amount?, override_max_amount?}
PATCH /catalog/price-lists/{id}/modifier-items обновить цены опций
body: {items:[{modifier_option_id, price}]}
Findings
| ID | Severity | Title |
|---|---|---|
| F30 | 🟡 | max_amount < min_amount принимается (BUG-044 confirmed) |
| F31 | 🟡 | Отрицательный min_amount принимается |
| F32 | 🟡 | Опция с отрицательной ценой принимается (потенциальный обход скидок) |
| F33 | 🟢 | Нет верхнего предела для max_amount (999999 принимается) |
| F34 | 🟢 | Группа без опций (options: []) принимается |
| F41 | 🟡 | PATCH product с modifier_group_ids не работает — нужен POST /products/{id}/modifiers |
| F42 | 🟢 | UX: при достижении max — нет подсказки на POS |
| F44 | 🟡 | POST /modifier-groups тихо игнорирует options[].price |
| F45 | 🟢 | DELETE modifier-group оставляет orphan записи в price-list/modifier-items |
| BUG-043 | 🟢 | UI: Описание в шрифте textarea |
| BUG-044 | 🟡 | (covered by F30/F31/F32) |
| BUG-045 | 🟢 | Имя опции: нет maxlength, принимает пробел |
| BUG-047 | 🟡 | Технология приготовления синхронизирована между опциями |
| BUG-048 | 🟡 | Не сохраняется удаление текста из «Технология приготовления» |
Тест-кейсы
TC-CATALOG-MOD-013 — Привязка группы к товару
Status: ✅ pass (через POST /products/{id}/modifiers) · TC-CHAIN-013
Связан с F41 — PATCH product с modifier_group_ids не работает.
TC-CATALOG-MOD-014 — Min/max enforce на POS
Status: ✅ pass UX (max не даёт превысить) · TC-CHAIN-014 F42 — UX без подсказки. F30/F31/F32 — backend без валидации.
TC-CATALOG-MOD-015 — Удалить группу — позиция в существующем заказе остаётся
Status: ◯ todo · TC-CHAIN-015 Создать заказ → DELETE modifier-group → открыть заказ — модификаторы должны остаться (denorm).
TC-CATALOG-MOD-016 — Изменить цену опции
Status: ✅ pass · TC-CHAIN-016
PATCH /price-lists/{id}/modifier-items с {items: [{modifier_option_id, price}]} → 200, новая цена применяется к новым заказам.
TC-CATALOG-MOD-030 — Валидация max < min (F30 / BUG-044)
Status: ❌ fail · session 2026-05-05
POST с min_amount=3, max_amount=1 → 201 (ожидание 400)
TC-CATALOG-MOD-031 — Отрицательный min (F31)
POST с min_amount=-1 → 201
TC-CATALOG-MOD-032 — Отрицательная цена опции (F32)
POST с options:[{name:"x", price:-100}] → 201
TC-CATALOG-MOD-033 — Огромный max (F33)
POST с max_amount=999999 → 201
TC-CATALOG-MOD-034 — Группа без опций (F34)
POST с options:[] → 201
TC-CATALOG-MOD-045 — DELETE не чистит price-list (F45)
Status: ❌ fail (session 2026-05-05)
- POST modifier-group
- DELETE
- GET /price-lists/{id}/items → modifier_items этой группы остались
Snippets
# Создать группу с опциями
echo '{"name":"test","type":"group","min_amount":1,"max_amount":2,"options":[{"name":"A"},{"name":"B"},{"name":"C"}]}' > /tmp/m.json
curl -sS -X POST "$B/modifier-groups" -H "$H" -H "Content-Type: application/json" --data-binary @/tmp/m.json
# Установить цену опции (правильный endpoint)
echo '{"items":[{"modifier_option_id":"<id>","price":10}]}' > /tmp/p.json
curl -sS -X PATCH "$B/catalog/price-lists/<pl_id>/modifier-items" -H "$H" -H "Content-Type: application/json" --data-binary @/tmp/p.json
# Привязать к товару
echo '{"modifier_group_id":"<group_id>","binding_type":"free"}' > /tmp/b.json
curl -sS -X POST "$B/catalog/products/<product_id>/modifiers" -H "$H" -H "Content-Type: application/json" --data-binary @/tmp/b.json