Техкарты (рецептуры)
Источник требований
Техкарта — описание состава блюда: ингредиенты, нормы расхода, потери при обработке, технология приготовления. Используется для автоматического списания ингредиентов со склада, расчёта себестоимости, прогноза остатков.
Сервис: Warehouse Service (:3008). Ссылается на товары и модификаторы из Catalog Service.
Фронт: таб “Техкарта” в карточке товара (рядом с табами Информация, Модификаторы). Только для товаров типа dish.
Техкарта
Привязана к товару (product_id). Изменения применяются напрямую.
Поля
| Поле | Обязательность | Описание |
|---|---|---|
| Товар | Обязательно | product_id → Catalog Service |
| Название | Обязательно | Обычно совпадает с товаром, может отличаться для вариантов |
| Выход готового | Обязательно | Вес/объём готовой порции (число + единица) |
| Технология приготовления | Необязательно | Текстовое описание шагов приготовления |
| Статус | Обязательно | active / inactive (default active) |
| Модификатор | Необязательно | modifier_option_id — для per-size вариантов (null = базовая техкарта) |
Типы техкарт по привязке
| Привязка | Пример | modifier_option_id |
|---|---|---|
| Базовая | Пицца Маргарита (без размеров) | null |
| Per-size | Пицца Маргарита 25 см | uuid опции “25 см” |
| Per-size | Пицца Маргарита 30 см | uuid опции “30 см” |
| Добавка | Доп. сыр (мини-рецептура) | uuid опции “Доп. сыр” |
Строка рецепта (RecipeItem)
Каждая строка — один ингредиент в рецептуре.
Поля
| Поле | Обязательность | Описание |
|---|---|---|
| Ингредиент | Обязательно | ingredient_id (FK → Warehouse ingredients) |
| Масса брутто | Обязательно | До обработки (число, >= 0) |
| Масса нетто | Обязательно | После обработки (число, >= 0, ⇐ брутто) |
| % потерь холодная обработка | Необязательно | Вычисляется или вводится вручную |
| % потерь горячая обработка | Необязательно | Вычисляется или вводится вручную |
| Единица измерения | Обязательно | г, кг, мл, л, шт |
| Порядок | Обязательно | Для сортировки строк |
Автовычисление потерь
При вводе брутто и нетто — % потерь вычисляется автоматически:
% потерь = (1 - нетто / брутто) × 100
При вводе брутто и % потерь — нетто вычисляется:
нетто = брутто × (1 - % / 100)
Ингредиенты
(BR 1.11: ингредиенты перенесены из Catalog в Warehouse Service)
Ингредиенты — отдельная сущность в Warehouse Service. Не продаются, не участвуют в каталогах и прейскурантах. Глобальный справочник франшизы.
Ингредиент-полуфабрикат (Исправлено в BUG-010)
Ингредиент может иметь собственную техкарту — в этом случае он является полуфабрикатом. Полуфабрикат — это не dish из Catalog, а ингредиент в Warehouse Service со своей рецептурой. См. Полуфабрикаты (вложенные рецептуры).
Поля ингредиента
| Поле | Обязательность | Описание |
|---|---|---|
| Название | Обязательно | Уникальное в рамках франшизы |
| Описание | Необязательно | Текстовое |
| Единица измерения | Обязательно | г, кг, мл, л, шт |
| Статус | Обязательно | active / inactive (default active) |
Создание ингредиентов
Ингредиенты создаются в контексте техкарты — при добавлении строки рецепта:
- Поиск по существующим ингредиентам (
GET /api/v1/ingredients?search=...— Warehouse Service) - Если не найден — кнопка “Создать ингредиент” → быстрая форма (название, единица измерения)
- API:
POST /api/v1/ingredients(Warehouse Service)
Ингредиенты управляются в отдельном разделе «Ингредиенты» в sidebar (/catalog/ingredients). (BR 1.12)
Ограничения
- Удаление: blocked если используется в рецептах (
INGREDIENT_IN_USE) - Смена единицы измерения: blocked если используется (
INGREDIENT_IN_USE) - Деактивация через
status=inactive— не удаляет, но скрывает из поиска при добавлении в новые рецепты
Полуфабрикаты (вложенные рецептуры)
(Исправлено в BUG-010)
Полуфабрикат = ингредиент в Warehouse Service, у которого есть собственная техкарта. Не dish из Catalog.
Пицца Маргарита (dish, техкарта):
├── Тесто (ингредиент-полуфабрикат, своя техкарта):
│ ├── Мука (ингредиент) — 150г
│ ├── Вода (ингредиент) — 80мл
│ └── Дрожжи (ингредиент) — 5г
├── Соус (ингредиент-полуфабрикат, своя техкарта):
│ └── Томаты (ингредиент) — 100г
└── Моцарелла (ингредиент) — 150г
Правила
- Полуфабрикат = ингредиент (
ingredientsв Warehouse), у которого есть техкарта (tech_cards.ingredient_id) - В строке рецепта всегда только
ingredient_id— без ссылок на Catalog - Себестоимость: система разворачивает цепочку до сырья (ингредиенты без техкарт)
- Глубина вложенности не ограничена (но UI показывает только 1 уровень, полный состав — по кнопке)
- Циклические ссылки запрещены (валидация при добавлении)
Себестоимость
Рассчитывается автоматически в реальном времени:
Себестоимость блюда = ∑(нетто_ингредиента × средняя_закупочная_цена_ингредиента)
- Средняя закупочная цена — средневзвешенная (Weighted Average), пересчитывается при каждой приёмке
- Для полуфабрикатов — себестоимость полуфабриката вычисляется рекурсивно
- Если цена ингредиента неизвестна (нет приёмок) — показать ”—” и предупреждение
Средневзвешенная цена (Обновлено в BR 1.14)
Средняя закупочная цена рассчитывается из складских партий (
stock_batches):SUM(purchase_price * quantity) / SUM(quantity)по партиям с qty > 0. Пересчитывается автоматически при каждом акте приёмки и списании. CostCalculationService используетGET /api/v1/ingredients/{id}/average-costдля получения актуальной цены. См. Склад (Phase 1).
Per-modifier техкарты
(Обновлено в BR 1.9.2)
Закреплённые модификаторы (structural)
Закреплённые модификаторы (binding_type = structural) определяют вариант блюда. Каждая опция = отдельная техкарта товара с modifier_option_id.
Маргарита + [Размер (structural): 25см, 30см, 35см]
→ Техкарта (modifier_option_id = null) — базовая (если нужна)
→ Техкарта (modifier_option_id = uuid_25cm)
→ Техкарта (modifier_option_id = uuid_30cm)
→ Техкарта (modifier_option_id = uuid_35cm)
В UI — закреплённые модификаторы отображаются в табе “Техкарта” конструктора товара (не в “Модификаторы”). Вкладки/табы per-option внутри таба.
Свободные модификаторы — добавки (BR 1.9.1)
(Обновлено в BR 1.9.1)
Техкарта добавки живёт на уровне опции модификатора в справочнике, не на уровне товара. При привязке модификатора к товару — техкарта автоматически применяется.
Таблица modifier_tech_cards (Warehouse Service):
- Привязана к
modifier_option_id - Одна техкарта на опцию — переиспользуется для всех товаров
Пример:
modifier_tech_cards:
modifier_option: "Доп. сыр" → [Моцарелла 50г]
Маргарита + Добавки → "Доп. сыр" автоматически берёт техкарту
Пепперони + Добавки → та же техкарта, без дублирования
Разделение по типу привязки (BR 1.9.2):
- Закреплённый (
binding_type = structural) → техкарта на уровне товара (tech_cards.modifier_option_id) - Свободный (
binding_type = free) → техкарта на уровне модификатора (modifier_tech_cards)
При продаже:
Маргарита 30 см + 2x Доп. сыр
→ tech_cards (product=Маргарита, modifier_option=30см) → Тесто, Соус, Моцарелла
→ modifier_tech_cards (modifier_option=Доп.сыр) → Моцарелла 50г × 2
Техкарты модификаторов всегда редактируемые — изменения применяются напрямую.
Где редактировать: в справочнике модификаторов → карточка группы → таблица опций → колонка “Техкарта”. См. Модификаторы.
Ролевая матрица
Франшиза (владелец бренда)
- CRUD техкарт всех товаров
- CRUD техкарт модификаторов (в справочнике) (BR 1.9.1)
- CRUD ингредиентов (справочник в Warehouse) (BR 1.11)
- Просмотр себестоимости
Франчайзи (партнёр)
- Просмотр техкарт активных товаров
- Просмотр себестоимости
Менеджер ТТ
- Просмотр техкарт
Кассир
- Нет доступа (авто-списание автоматическое)
Конвертация единиц
Справочник конвертации для случаев когда единица в каталоге отличается от единицы в рецептуре.
| Поле | Описание |
|---|---|
| Продукт | product_id |
| Из единицы | ”упаковка”, “бутылка” |
| В единицу | ”г”, “мл” |
| Коэффициент | Пример: 1 упаковка = 250г → factor=250 |
Франшиза настраивает конвертацию при первом использовании ингредиента в рецепте.
Что НЕ входит
- Генерация PDF для ТТК — Phase 2
- Расчёт КБЖУ — Phase 2
- Авто-стоп-лист по остаткам — BR 1.11
- Авторекомендация заказа ингредиентов — отдельная BR (склад)
- Импорт техкарт из Excel — Phase 2
- Складские остатки, приёмки, списания — отдельная BR (склад)
Связи с другими модулями
- Каталог — товары (product_id), таб Техкарта в конструкторе товара
- Модификаторы — per-size техкарты через modifier_option_id
- Прейскуранты (BR 1.10) — цены влияют на себестоимость? Нет, себестоимость = закупочные цены, не продажные
- Стоп-листы (BR 1.11) — авто-стоп по остаткам (зависит от техкарт + складских остатков)