Склад
Бизнес-спека
Routes
| Route | Страница |
|---|---|
/warehouse/inventory | Остатки |
/warehouse/receipt-acts | Список приёмок |
/warehouse/receipt-acts/:id | Карточка приёмки |
/warehouse/write-off-acts | Список списаний |
/warehouse/write-off-acts/:id | Карточка списания |
Sidebar
Группа “Склад” в навигации (после “Каталог”), видна всем ролям кроме Кассира.
Пункты:
- Остатки (
/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
- Поиск ингредиента (API:
-
“Убрать” строку (только 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, кнопки добавления/удаления скрыты
Footer
Итого: 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 “Недостаточно остатков”
Footer
Итого: total_cost ₽