Склад

Бизнес-спека

Routes

RouteСтраница
/warehouse/inventoryОстатки
/warehouse/receipt-actsСписок приёмок
/warehouse/receipt-acts/:idКарточка приёмки
/warehouse/write-off-actsСписок списаний
/warehouse/write-off-acts/:idКарточка списания

Группа “Склад” в навигации (после “Каталог”), видна всем ролям кроме Кассира.

Пункты:

  • Остатки (/warehouse/inventory)
  • Приёмки (/warehouse/receipt-acts)
  • Списания (/warehouse/write-off-acts)

1. Остатки (InventoryPage)

Layout

  • Header: “Остатки”
  • Store selector — дропдаун выбора ТТ (как в Стоп-листах)
  • Поиск по названию ингредиента (client-side фильтр)
  • Таблица остатков

Store selector

РольПоведение
ФраншизаДропдаун со всеми ТТ
ФранчайзиДропдаун только с собственными ТТ
Менеджер ТТАвтовыбор единственной ТТ, дропдаун disabled

API: GET /api/v1/admin/stores выбор ТТ GET /api/v1/admin/warehouse/warehouses поиск склада по store_id GET /api/v1/admin/warehouse/stock-balances?warehouse_id=...

Таблица

КолонкаДанные
Ингредиентingredient_name
Ед. изм.unit_of_measure
Текущий остатокcurrent_quantity
Средняя ценаaverage_cost (формат: ₽ или ”---“)
Обновленоupdated_at (формат: dd.mm.yyyy HH:mm)

Состояния

  • Нет выбранной ТТ: “Выберите торговую точку”
  • Нет данных: “Нет данных по остаткам”
  • Загрузка: skeleton-строки

Ролевой доступ

РольДоступ
ФраншизаПросмотр остатков всех ТТ
ФранчайзиПросмотр остатков своих ТТ
Менеджер ТТПросмотр остатков своей ТТ
КассирНет доступа (раздел скрыт)

2. Список приёмок (ReceiptActListPage)

Layout

  • Header: “Приёмки”
  • Store selector (аналогично остаткам)
  • Фильтр по статусу (Все / Черновик / Проведён)
  • Кнопка “Создать приёмку”
  • Таблица приёмок

Таблица

КолонкаДанные
Номерdocument_number (ссылка на карточку)
Датаreceipt_date (формат: dd.mm.yyyy)
Статусbadge: “Черновик” (серый) / “Проведён” (зелёный)
Суммаtotal_amount
Комментарийcomment или ”---”

API: GET /api/v1/admin/warehouse/receipt-acts?warehouse_id=...&status=...

Действия

  • “Создать приёмку”POST /api/v1/admin/warehouse/receipt-acts { warehouse_id, receipt_date: now } навигация на карточку
  • Клик по номеру /warehouse/receipt-acts/:id

Ролевой доступ

РольПросмотрСоздание
ФраншизаВсе ТТДа
ФранчайзиСвои ТТДа
Менеджер ТТСвоя ТТДа
КассирНетНет

3. Карточка приёмки (ReceiptActDetailPage)

Layout

  • Header: document_number + badge статуса
  • Поля: дата приёмки, комментарий
  • Таблица строк
  • Footer: итого

Поля (draft)

ПолеТипРедактируемо
Дата приёмкиdate inputДа (только draft)
КомментарийtextareaДа (только draft)

Кнопка “Сохранить” — PATCH /api/v1/admin/warehouse/receipt-acts/:id

Таблица строк

КолонкаДанные
Ингредиентingredient_name
Кол-воquantity
Ед. изм.unit_of_measure
Цена за ед.unit_price
Суммаline_total
Срок годностиshelf_life_date или ”---“
Действия”Убрать” (только draft)

Действия

  • “Добавить строку” (только draft) — модалка:

    • Поиск ингредиента (API: GET /api/v1/admin/warehouse/ingredients?search=...)
    • Кол-во (number input)
    • Цена за ед. (number input)
    • Ед. изм. (text input)
    • Срок годности (date input, необязательно)
    • POST /api/v1/admin/warehouse/receipt-acts/:id/lines
  • “Убрать” строку (только draft) — DELETE /api/v1/admin/warehouse/receipt-acts/:id/lines/:lineId

  • “Провести” (только draft) — confirm modal POST /api/v1/admin/warehouse/receipt-acts/:id/post

    • После проведения: все поля read-only, кнопки добавления/удаления скрыты

Итого: total_amount

Состояния

  • status === "draft" — редактируемый режим
  • status === "posted" — read-only режим

4. Список списаний (WriteOffActListPage)

Layout

Аналогично списку приёмок.

Таблица

КолонкаДанные
Номерdocument_number (ссылка на карточку)
Датаwrite_off_date (формат: dd.mm.yyyy)
Причинаreason
Статусbadge: “Черновик” / “Проведён”
Стоимостьtotal_cost

API: GET /api/v1/admin/warehouse/write-off-acts?warehouse_id=...&status=...

Действия

  • “Создать списание”POST /api/v1/admin/warehouse/write-off-acts { warehouse_id, write_off_date: now, reason: "" } навигация на карточку

Ролевой доступ

Аналогично приёмкам.


5. Карточка списания (WriteOffActDetailPage)

Layout

Аналогично карточке приёмки.

Поля (draft)

ПолеТипРедактируемо
Дата списанияdate inputДа (только draft)
Причинаtext input (обязательно)Да (только draft)

Таблица строк

КолонкаДанные
Ингредиентingredient_name
Кол-воquantity
Себестоимость ед.unit_cost ₽ (read-only, из avg cost)
Стоимость строкиline_cost
Действия”Убрать” (только draft)

Действия

  • “Добавить строку” (только draft) — модалка:

    • Поиск ингредиента
    • Кол-во (number input) — unit_cost рассчитывается автоматически
    • POST /api/v1/admin/warehouse/write-off-acts/:id/lines
  • “Убрать” строку — DELETE /api/v1/admin/warehouse/write-off-acts/:id/lines/:lineId

  • “Провести” — confirm modal POST /api/v1/admin/warehouse/write-off-acts/:id/post

Ошибки

  • INSUFFICIENT_STOCK toast “Недостаточно остатков”

Итого: total_cost