Торговые точки — Карточка

Три режима одного экрана: просмотр, создание, редактирование.


Просмотр (/stores/:id)

API: GET /api/v1/stores/{id}

Что видит пользователь

Заголовок — название ТТ. Рядом — бейдж статуса (Черновик — серый, Опубликована — зелёный, Приостановлена — красный).

Кнопки в шапке (видимость по роли):

КнопкаВидимостьЧто происходит
”Редактировать”Franchise — всегда; Franchisee — свои; Manager — свояПереход в /stores/{id}/edit
”Опубликовать”Franchise + status=draftPOST /api/v1/stores/{id}/publish, toast “Торговая точка опубликована"
"Снять с публикации”Franchise + status=publishedPOST /api/v1/stores/{id}/unpublish, toast “Торговая точка снята с публикации"
"Удалить”FranchiseМодалка (см. логику удаления)

Блоки данных

Основные данные:

ПолеЗначение
Названиеname
Адресaddress
Широтаlatitude
Долготаlongitude
Городcity или ”—“
Телефонphone или ”—“
Emailemail или ”—“
ЮЛlegal_entity.name — кликабельная ссылка на /legal-entities/{legal_entity_id}

График работы:

Таблица на 7 дней:

ДеньОткрытиеЗакрытиеВыходной
Понедельникschedule[0].open_timeschedule[0].close_time”Выходной” если is_closed=true
Вторникschedule[1].open_timeschedule[1].close_time
Средаschedule[2].open_timeschedule[2].close_time
Четвергschedule[3].open_timeschedule[3].close_time
Пятницаschedule[4].open_timeschedule[4].close_time
Субботаschedule[5].open_timeschedule[5].close_time
Воскресеньеschedule[6].open_timeschedule[6].close_time

Если is_closed=true — вместо времени отображается текст “Выходной” серым цветом.

Дополнительные секции на карточке просмотра

На странице /stores/:id в режиме просмотра под блоком графика работы отображаются три секции (каждая — отдельный компонент):

1. POS-терминалы (TerminalsSection) — файл pages/stores/TerminalsSection.tsx

  • Список POS-терминалов привязанных к ТТ
  • Колонки: название (label), заводской номер ФН (fs_number), РН ККТ (rn_kkt), статус (active/inactive), последняя активность (last_seen_at)
  • Действия: добавить терминал, редактировать (label/rn_kkt/status), удалить
  • Role-guard: Franchise — CRUD; Franchisee/Manager — только view

2. Столы зала (TablesSection) — файл pages/stores/TablesSection.tsx

  • Canvas-визуализация столов с drag&drop (позиции position_x/position_y)
  • Статусы: free / occupied / reserved (цветовая индикация)
  • При выделении стола — редактор номера, метки, вместимости, управление бронью (occupy/release/reserve/cancel-reservation)
  • Если стол занят — отображается номер текущего заказа (current_order_id с ссылкой)
  • Role-guard: Franchise — CRUD; Manager/Cashier своей ТТ — управление статусами

3. Интеграции (IntegrationsSection) — файл pages/stores/IntegrationsSection.tsx

  • Список подключений к агрегаторам (Я.Еда, Маркет Деливери)
  • Колонки: провайдер, external_restaurant_id, статус подключения, последняя синхронизация меню
  • Действия: синхронизировать меню, открыть лог операций, редактировать credentials, отключить
  • Role-guard: Franchise — управление; остальные — read-only

4. Терминал PayKeeper (PaykeeperTerminalSection) — файл pages/stores/PaykeeperTerminalSection.tsx (BR 3.3)

  • Видна только если у ЮЛ этой ТТ активна PK-интеграция
  • В состоянии «не привязан»: empty state + кнопка «Привязать терминал» (при integrations.manage)
  • В состоянии «привязан»: блок с полями pk_terminal_id, pk_mpos_merchant_id, label, статус
  • Действия: редактировать (модалка с полями), отвязать (с подтверждением; блокируется если есть открытые инвойсы)
  • Role-guard: integrations.manage — CRUD; integrations.read (менеджер ТТ) — только просмотр
  • Детали — отдельная спека

Создание (/stores/new)

API: POST /api/v1/stores Доступ: только Franchise

Что видит пользователь

Заголовок: “Новая торговая точка”. Форма с полями.

Форма

Основные данные:

ПолеТип вводаОбязательноМаска/Валидация
НазваниеText inputДаmax 255
АдресText inputДаmax 500
ШиротаNumber inputДа-90..90, до 6 знаков после точки
ДолготаNumber inputДа-180..180, до 6 знаков после точки
ГородText inputНетmax 255
ТелефонText inputНет+7 (XXX) XXX-XX-XX
EmailText inputНетemail
ЮЛSelectДаСписок активных ЮЛ (GET /api/v1/legal-entities?status=active)
Часовой поясSelectНетDefault “Europe/Moscow”. Список часовых поясов РФ

(Доработано в BUG-008)

Поле "ЮЛ" нельзя изменить после создания

При создании — обычный select. После создания — disabled с tooltip “ЮЛ нельзя изменить после создания”.

График работы:

(Доработано в BUG-008)

7 строк (Понедельник — Воскресенье), в каждой:

ЭлементТипОписание
День неделиLabelПн / Вт / Ср / Чт / Пт / Сб / Вс
Время открытияSelect (часы 00-23) + Select (минуты 00/15/30/45)Формат 24h, disabled если “Выходной”
Время закрытияSelect (часы 00-23) + Select (минуты 00/15/30/45)Формат 24h, disabled если “Выходной”
ВыходнойCheckboxПри включении — очищает и блокирует поля времени

Быстрая настройка:

  • Checkbox “Одинаковый для всех дней” — при включении время и состояние “Выходной” из первой строки (Понедельник) копируется во все остальные дни
  • При изменении значений в первой строке — синхронизация в реальном времени
  • При отключении — каждый день становится независимым (значения сохраняются)

Валидация

  • На клиенте: обязательные поля, формат координат, email, телефон
  • С сервера: дубликат названия в рамках ЮЛ (NAME_DUPLICATE), невалидное ЮЛ (LEGAL_ENTITY_NOT_FOUND)
  • Ошибки сервера показываются под соответствующим полем

Кнопки

  • “Сохранить” — отправить форму
  • “Отмена” — возврат на список (с подтверждением если есть несохранённые данные)

После успеха

  • Redirect на /stores/{new_id} (карточка просмотра)
  • Toast: “Торговая точка создана”

Редактирование (/stores/:id/edit)

API: PATCH /api/v1/stores/{id} Доступ: Franchise — все поля (кроме ЮЛ); Franchisee — свои ТТ; Manager — своя ТТ

Что видит пользователь

Та же форма что при создании, но:

  • Поле ЮЛdisabled, серый фон, tooltip “ЮЛ нельзя изменить после создания”
  • Предзаполнены текущие значения

Franchise — полный доступ

Все поля редактируемы, кроме ЮЛ.

Franchisee / Manager — ограничения

Редактируемые поля:

  • Название
  • Адрес
  • Широта, Долгота
  • Город
  • Телефон
  • Email
  • График работы

Нельзя менять: ЮЛ (disabled для всех ролей).

Кнопки

  • “Сохранить” — отправить PATCH
  • “Отмена” — возврат на карточку просмотра

После успеха

  • Redirect на /stores/{id} (карточка просмотра)
  • Toast: “Изменения сохранены”

Состояния

СостояниеЧто показываем
Загрузка (просмотр/edit)Skeleton-блоки вместо полей
ТТ не найдена (404)“Торговая точка не найдена” + кнопка “Вернуться к списку”
Ошибка сохраненияОшибки под полями (validation) или toast (серверная ошибка)
Несохранённые измененияПри уходе со страницы: “У вас есть несохранённые изменения. Покинуть страницу?”

Переходы

ОткудаКудаТриггер
КарточкаСписокКнопка “Назад” / breadcrumb
КарточкаРедактированиеКнопка “Редактировать”
СозданиеКарточкаПосле успешного сохранения
СозданиеСписокКнопка “Отмена”
РедактированиеКарточкаПосле сохранения или “Отмена”

Прейскурант

(BR 1.10)

Поле “Прейскурант” в карточке ТТ (только Franchise).

  • Тип: Select
  • Опции: Все active прейскуранты + “По умолчанию (дефолтный)”
  • Default: “По умолчанию” (price_list_id = null)
  • API назначение: PATCH /api/v1/stores/{id}/price-list{ "price_list_id": "uuid" }
  • API снятие: DELETE /api/v1/stores/{id}/price-list
  • Видимость: Только Franchise. Franchisee/Manager видят текущий прейскурант (read-only).

Ссылки