BR 1.14: Склад Phase 1 — остатки, приёмки, списания
Зависит от:
Контекст
Для расчёта себестоимости блюд нужны закупочные цены ингредиентов. Закупочные цены появляются из приёмок на склад. Склад также нужен для контроля остатков — знать сколько чего есть на каждой ТТ.
В YumaPos складской учёт включает: склады per-store, приёмки (акты прихода), списания, перемещения, инвентаризацию, производство. Phase 1 — минимум: склады + приёмки + списания + остатки.
Только бэкенд (Warehouse Service). Фронт — отдельная BR.
Требования
1. Склады (warehouses)
- Один склад на торговую точку — создаётся автоматически при создании ТТ
- Название склада = название ТТ
- Нельзя создать вручную, нельзя удалить (привязан к жизненному циклу ТТ)
- Склад принадлежит franchise_id + store_id
2. Складские остатки (stock balances)
- Текущее количество каждого ингредиента на каждом складе
- Обновляется автоматически при проводке документов (приёмка +, списание −)
- Поля: warehouse_id, ingredient_id, current_quantity, unit_of_measure, last_updated
- Остатки не могут быть отрицательными (валидация при списании)
3. Складские партии (stock batches)
- Каждая приёмка создаёт партию с закупочной ценой
- Поля: warehouse_id, ingredient_id, purchase_price, quantity, received_date, shelf_life_date (опционально)
- При списании — FIFO (первая поступившая партия списывается первой)
- Средневзвешенная цена = сумма(цена × количество) / общее количество по всем партиям с qty > 0
4. Акты приёмки (receipt acts)
Документ поступления ингредиентов на склад.
Жизненный цикл: draft → posted
- draft — можно редактировать (добавлять/удалять строки, менять количества)
- posted — зафиксирован, создаёт партии, обновляет остатки. Нельзя редактировать.
Поля документа:
- Склад (warehouse_id)
- Номер документа (автоинкремент per franchise)
- Дата приёмки
- Комментарий (опционально)
- Статус (draft / posted)
- Общая сумма (вычисляется из строк)
Строки документа:
- Ингредиент (ingredient_id)
- Количество
- Единица измерения
- Цена за единицу (закупочная)
- Сумма строки (кол-во × цена)
- Срок годности (опционально)
При проводке (post):
- Для каждой строки создать stock_batch (партия)
- Обновить stock_balance (+quantity)
- Пересчитать average_cost ингредиента на этом складе
- Заблокировать редактирование документа
Без поставщика — Phase 1 без справочника поставщиков. Просто “поступление на склад”.
5. Акты списания (write-off acts)
Документ списания ингредиентов со склада (порча, истечение срока, недостача).
Жизненный цикл: draft → posted
Поля документа:
- Склад (warehouse_id)
- Номер документа
- Дата списания
- Причина (текст, обязательно)
- Статус (draft / posted)
- Общая стоимость списания (вычисляется)
Строки документа:
- Ингредиент (ingredient_id)
- Количество к списанию
- Себестоимость единицы (из средневзвешенной цены)
- Стоимость строки
При проводке:
- Проверить что на складе достаточно остатков
- Списать по FIFO (с самых старых партий)
- Обновить stock_balance (−quantity)
- Зафиксировать стоимость списания
Валидация: нельзя списать больше чем есть на складе.
6. Средневзвешенная цена (average cost)
- Per-ingredient per-warehouse
- Формула:
∑(batch.purchase_price × batch.quantity) / ∑(batch.quantity)гдеbatch.quantity > 0 - Пересчитывается при каждой приёмке и списании
- Используется для расчёта себестоимости в техкартах (CostCalculationService)
Бизнес-правила
- Склад = ТТ — один склад на ТТ, автоматическое создание
- Draft → Posted — документ проводится один раз, после этого неизменяем
- FIFO — при списании сначала расходуются самые старые партии
- Неотрицательные остатки — нельзя списать больше чем есть
- Средневзвешенная — цена считается по партиям с положительным количеством
- Единица измерения — при приёмке/списании должна совпадать с единицей ингредиента (или использовать unit_conversions)
Ролевой доступ
| Действие | Франшиза | Франчайзи | Менеджер | Кассир |
|---|---|---|---|---|
| Просмотр остатков | Все склады | Свои склады | Свой склад | Нет |
| Создать приёмку | Любой склад | Свои склады | Свой склад | Нет |
| Провести приёмку | Любой склад | Свои склады | Свой склад | Нет |
| Создать списание | Любой склад | Свои склады | Свой склад | Нет |
| Провести списание | Любой склад | Свои склады | Свой склад | Нет |
| Просмотр средней цены | Все | Свои | Свой | Нет |
Затронутые сервисы
| Сервис | Что меняется |
|---|---|
| Warehouse Service | Новые таблицы: warehouses, stock_balances, stock_batches, receipt_acts, receipt_act_lines, write_off_acts, write_off_act_lines. Новые CRUD + post эндпоинты. Обновление CostCalculationService для average_cost. |
| Store Service | При создании ТТ — Kafka-событие store.created → Warehouse создаёт склад. Или синхронный вызов. |
Что НЕ входит (Phase 2+)
- Поставщики (справочник контрагентов)
- Акты перемещения между складами
- Инвентаризация (сверка факт vs учёт)
- Акты производства (списание по техкарте при изготовлении)
- Автоматическое списание при продаже (интеграция с Order Service)
- Авто-стоп по остаткам (интеграция со стоп-листами)
- Фронт-интерфейс складского учёта
- Партионный учёт по срокам годности (алерты)
- Возвраты поставщику
Ссылки
- Техкарты — себестоимость зависит от закупочных цен
- Warehouse Service
- YumaPos:
_reference/yumapos/inventory-items.md,acceptance-acts.md,write-off-acts.md