Техкарты (рецептуры)

Источник требований

Техкарта — описание состава блюда: ингредиенты, нормы расхода, потери при обработке, технология приготовления. Используется для автоматического списания ингредиентов со склада, расчёта себестоимости, прогноза остатков.

Сервис: 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)

Создание ингредиентов

Ингредиенты создаются в контексте техкарты — при добавлении строки рецепта:

  1. Поиск по существующим ингредиентам (GET /api/v1/ingredients?search=... — Warehouse Service)
  2. Если не найден — кнопка “Создать ингредиент” → быстрая форма (название, единица измерения)
  3. 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) — авто-стоп по остаткам (зависит от техкарт + складских остатков)

Ссылки