ADR-010: Версионность техкарт и метод расчёта себестоимости
Статус
proposed — два открытых вопроса из BR 1.9
Вопрос 1: Версионность техкарт
В чём проблема
Франшиза меняет рецепт пиццы: убрала оливки, добавила рукколу. Техкарта перезаписана. Теперь:
- Себестоимость за прошлый месяц — считалась по старому рецепту (с оливками). Но техкарта уже новая (с рукколой). Если пересчитать — цифра изменится. Отчёт за прошлый месяц “поплывёт”.
- Списание ингредиентов — вчера продали 10 пицц по старому рецепту (списали оливки). Сегодня рецепт новый. Если кто-то смотрит “почему списались оливки?” — в текущей техкарте оливок нет.
- Аудит Роспотребнадзора — проверяющий спрашивает “по какому рецепту готовили в марте?“. Если техкарта перезаписана — ответа нет.
Рассмотренные варианты
A. Мутабельно (как каталог) + аудит-лог (ADR-008)
Техкарта перезаписывается. Аудит-лог фиксирует: “2026-04-15, убран ингредиент оливки, добавлена руккола”. История есть, но как diff-записи, не как полные снапшоты.
| Плюс | Минус |
|---|---|
| Просто — одна запись в БД | Нельзя “восстановить” старый рецепт как целый объект |
| Аудит-лог уже планируется (ADR-008) | Для отчётов нужно “восстановить” рецепт из цепочки дифов — сложно |
| Как в iiko (мутабельно) | Роспотребнадзор: формально ТТК должна быть документом, не цепочкой правок |
B. Версионность (как меню BR 1.11)
Каждое изменение = новая версия техкарты. Старые версии в архиве. Published-версия используется для списания.
| Плюс | Минус |
|---|---|
| Полная история, можно посмотреть рецепт на любую дату | Сложнее: таблица версий, lifecycle |
| Отчёты за период — по версии, актуальной на тот момент | Overhead для частых мелких правок |
| Роспотребнадзор: ТТК = конкретная версия документа | |
| Откат к старому рецепту — одной кнопкой |
C. Мутабельно + периодические снапшоты
Техкарта мутабельна. Но при каждом списании (продаже) в строке списания сохраняется snapshot рецепта (как снапшот цены в заказе).
| Плюс | Минус |
|---|---|
| Каждое списание самодостаточно | Огромный объём данных (снапшот рецепта × каждая продажа) |
| Не нужна версионность техкарты | Нельзя посмотреть “рецепт в марте” без анализа списаний |
Рекомендация
Вариант A на MVP — мутабельно + аудит-лог. Как в iiko. Достаточно для операционной работы. Если понадобится полная версионность (Роспотребнадзор, детальная аналитика) — перейти к варианту B. Переход аддитивный (добавить таблицу версий), не рефакторинг.
Решение
Ожидает подтверждения.
Вопрос 2: Метод расчёта себестоимости
В чём проблема
Себестоимость блюда = сумма (количество_ингредиента × цена_ингредиента). Но какая цена ингредиента? Мука закупалась трижды по разным ценам:
| Дата | Закупка | Цена за кг | Остаток после |
|---|---|---|---|
| 1 марта | 50 кг | 60₽/кг | 50 кг |
| 10 марта | 30 кг | 65₽/кг | 62 кг (12 осталось от первой + 30 новых + 20 со второй) |
| 20 марта | 20 кг | 70₽/кг | 45 кг |
Сегодня продали пиццу, в рецепте 0.2 кг муки. Себестоимость муки в этой пицце = 0.2 × ???.
Рассмотренные варианты
A. По последней закупке (Last Purchase Price)
Цена = 70₽/кг (последний акт прихода). Себестоимость муки = 0.2 × 70 = 14₽.
| Плюс | Минус |
|---|---|
Просто — одно поле last_price | Не отражает реальность: на складе ещё есть мука по 60₽ |
| Легко реализовать | Скачки себестоимости при каждой закупке |
| Быстро | Может искажать маржу |
B. Средневзвешенная (Weighted Average Cost)
Цена = (50×60 + 30×65 + 20×70) / (50+30+20) = 63.5₽/кг. Пересчитывается при каждом приходе. Себестоимость = 0.2 × 63.5 = 12.7₽.
| Плюс | Минус |
|---|---|
| Сглаживает скачки | Нужен пересчёт при каждом приходе |
| Отражает среднюю реальную стоимость | Не учитывает какая именно мука используется |
| Стандарт в общепите | Чуть сложнее |
| Так работает iiko |
C. FIFO (First In, First Out)
Сначала списывается мука по 60₽ (она пришла первой), потом по 65₽, потом по 70₽. Себестоимость зависит от порядка.
| Плюс | Минус |
|---|---|
| Максимально точно | Сложная реализация: нужно отслеживать партии |
| Бухгалтерски корректно | Нужна партионность на складе |
| Overhead для общепита (не промышленный склад) |
Как в iiko
iiko использует средневзвешенную (Weighted Average). При каждом акте прихода пересчитывает среднюю цену: (старый_остаток × старая_цена + новый_приход × новая_цена) / (старый_остаток + новый_приход). Это стандарт для общепита.
Рекомендация
Вариант B — средневзвешенная. Стандарт отрасли, используется в iiko, баланс между точностью и простотой. FIFO — overkill для общепита. По последней закупке — слишком грубо.
Решение
Ожидает подтверждения.
Последствия
При выборе A (мутабельно) + B (средневзвешенная)
- Техкарта — одна запись, перезаписывается. Аудит-лог фиксирует diff.
- Себестоимость блюда пересчитывается при каждом акте прихода (изменении средней цены ингредиента).
- Warehouse Service хранит
average_costper-ingredient per-store. Обновляется формулой при каждом приходе. - Простая реализация, как в iiko.
Риски
- Мутабельные техкарты: при аудите Роспотребнадзора может не хватить diff-лога. Потребуется перейти к версионности.
- Средневзвешенная: при резком скачке цен (инфляция) себестоимость реагирует с задержкой (старый дешёвый остаток “сглаживает”).