Расписание меню (Menu Availability)

Зачем

Бизнес-ланчи, утреннее меню, ночная карта — позиции которые должны быть видны в POS только в определённое окно. В отличие от временных тарифов здесь не меняется цена — позиция либо есть в меню, либо её нет.

Сущность

MenuAvailability:

ПолеТипОписание
idUUID
franchise_idUUIDТенант
namestring ≤100«Бизнес-ланч», «Утреннее меню»
days_of_weekint[]ISO 1=Пн..7=Вс
time_from / time_toTIMEОкно действия; time_from < time_to
scopeenumcategories / products (без all — закрытие всего меню = закрытие ТТ)
target_idsUUID[]Категории или товары (≥1)
store_idsUUID[]На какие ТТ распространяется (≥1)
statusenumactive / disabled
created_at, updated_atTIMESTAMP

Логика видимости

Для пары (store, product, now):

  1. Не упомянут ни в одном MenuAvailability → виден (default).
  2. Упомянут хотя бы в одном, и сейчас попадает в окно хотя бы одного → виден.
  3. Упомянут, но now не попадает ни в одно из окон → скрыт.

Один товар может относиться к нескольким окнам — например, бизнес-ланч 12-16 + утренний 8-11. Тогда виден в любое из двух окон.

Где применяется

СлойПоведение
POS меню (/internal/catalog/menu?store_id=X)Скрытые позиции отфильтровываются — кассир их не видит
POS заказНевозможно — позиция не выбирается из меню
Инвойс PayKeeperНе попадает в cart → не на чек
Каталог в ЛК PKНе трогается — там полный каталог. Это OK: доступность определяется на уровне POS, а не PK

Бизнес-правила

  • Per-ТТ. Расписание относится к конкретным ТТ.
  • Только повторяющиеся окна. Одноразовые исключения вне scope.
  • Нет конфликта с временными тарифами. Скидка может действовать на товар, который сейчас скрыт расписанием — товар просто не появится в меню, и тариф к нему никто не применит.
  • Пересечение с ручным стоп-листом. Если позиция вручную в стоп-листе — скрыта приоритетнее. Расписание добавляет автоматическое скрытие сверху.

Ролевая матрица

РольListViewCRUD
Владелец франшизы✅ все ТТ✅ все ТТ
Владелец партнёра✅ свои ТТ✅ свои✅ свои ТТ
Менеджер ТТ
Кассир

Permissions: menu.read для GET, menu.edit для CRUD (переиспользуем).

UI

Страница Каталог → Расписание меню:

  • Сначала пикер ТТ (как в Временные тарифы).
  • После выбора ТТ — список расписаний этой ТТ + «Добавить расписание».
  • Форма: название, дни недели, окно, scope (Товары / Категории), пикер с поиском и группировкой товаров по категориям.

Точность времени

Кэш активных окон ТТ — 30 сек. POS подгружает меню при загрузке страницы кассы или периодически — задержка реальная ≤30 сек после фактического начала/конца окна.

Что НЕ поддерживается

  • One-off (одноразовые) окна.
  • Закрытие ТТ целиком (для этого есть отдельные механизмы — расписание работы ТТ, suspended status).
  • Минимальное количество и порядок: «бизнес-ланч из 3 позиций» не разрешает сборку только из 2-х. Это бизнес-правило ресторана, не каталог.

Ссылки