Расход товаров и заготовок в Айко с учетом вложенных технологических карт
Задача: рассчитать в Айко расход товара (скажем, "Лосось филе") за день. При условии, что в ресторане заданы вложенные технологические карты и в меню есть составные блюда.
Здесь и далее используются реальные данные реального Клиента, идентификаторы и названия товаров/заготовок/блюд частично "урезаны" для сохранения конфиденциальности.
Дано
В меню ресторана есть три блюда:
- Ролл "Маки с лососем" #35c811e50188.
- Ролл "Филадельфия с лососем" #35c811e501a7.
- Cет "Сет для двоих" #2d2536539600, в составе которого один ролл "Маки с лососем" и один ролл "Филадельфия с лососем".
В Айко (iiko) заданы технологические карты:
- Для приготовления 1 кг заготовки "Лосось филе очищенное ПФ" #66e1ee4f2fcc нужно взять 1.299 кг товара "Лосось филе" #35c811e501c6.
- Для приготовления 1 блюда "Маки с лососем" #35c811e50188 нужно взять 0.092 кг риса, 1 лист нори и 0.05 кг заготовки "Лосось филе очищенное ПФ" #66e1ee4f2fcc.
- Для приготовления 1 блюда "Филадельфия с лососем" #35c811e501a7 нужно взять 0.145 кг риса, 1 лист нори, 0.06 кг крем-сыра, 0.045 кг огурца и 0.1 кг заготовки "Лосось филе очищенное ПФ" #66e1ee4f2fcc.
- Для приготовления 1 сета "Сет для двоих" #2d2536539600 нужно взять 1 блюдо "Маки с лососем" #35c811e50188 и одно блюдо "Филадельфия с лососем" #35c811e501a7.
Найти
Менеджер знает, сколько отдельно роллов "Маки с лососем" и "Филадельфия с лососем" было продано за день, сколько было продано сетов "Сет для двоих" за день.
И ему необходимо узнать, сколько же было потрачено лосося за день? Другими словами, какой расход товара "Лосось филе" #35c811e501c6 за день с учетом вложенности технологических карт?
Решение вручную
Схематично дерево приготовления блюд с учетом вложенных технологических карт можно представить в виде:
Состав блюда "Маки с лососем" #35c811e50188: 1. 0.092 кг риса. 2. Один лист нори. 3. 0.05 кг заготовки "Лосось филе очищенное ПФ" #66e1ee4f2fcc. Состав: 1. 1.299 кг товара "Лосось филе" #35c811e501c6 Состав блюда "Филадельфия с лососем" #35c811e501a7: 1. 0.145 кг риса. 2. Один лист нори. 3. 0.06 кг крем-сыра. 4. 0.045 кг огурца. 5. 0.1 кг заготовки "Лосось филе очищенное ПФ" #66e1ee4f2fcc. Состав: 1. 1.299 кг товара "Лосось филе" #35c811e501c6 Состав блюда "Сет для двоих" #2d2536539600: 1. Одно блюдо "Маки с лососем ПФ" #35c811e50188. Состав: 1. 0.092 кг риса. 2. Один лист нори. 3. 0.05 кг заготовки "Лосось филе очищенное ПФ" #66e1ee4f2fcc. Состав: 1. 1.299 кг товара "Лосось филе" #35c811e501c6 2. Одно блюдо "Филадельфия с лососем" #35c811e501a7. Состав: 1. 0.145 кг риса. 2. Один лист нори. 3. 0.06 кг крем-сыра. 4. 0.045 кг огурца. 5. 0.1 заготовки "Лосось филе очищенное ПФ" #66e1ee4f2fcc. Состав: 1. 1.299 кг товара "Лосось филе" #35c811e501c6
Если вручную посчитать, то в одном блюде "Маки с лососем" содержится 0.05 кг заготовки "Лосось филе очищенное ПФ" или 0.05 * 1.299 = 0.06495 кг товара "Лосось филе".
По аналогии: в одном блюде "Филадельфия с лососем" cодержится 0.1 * 1.299 = 0.1299 кг товара "Лосось филе".
В блюде "Сет для двоих" содержится 0.06495 + 0.1299 = 0.19485 кг товара "Лосось филе".
Чтобы дать ответ менеджеру, необходимо построить отчет о продажах за день и сложить произведения:
1. Количество проданных блюд "Маки с лососем" * 0.06495.
2. Количество проданных блюд "Филадельфия с лососем" * 0.1299.
3. Количество проданных блюд "Сет для двоих" * 0.19485.
Но как быть, когда много вложенных технологических карт и много составных блюд в меню? Пробуем построить автомат для решения задачи.
Автоматизация решения
Для решения поставленной задачи внешний разработчик может воспользоваться методами "серверного апи Айко" — iikoServer API. Как подключить внешние интеграции к серверу Айко (iiko) по API
Знакомимся с официальной документацией и экспериментируем с доступными методами API.
1 вариант. Расход продуктов по продажам
А если запросить расход товара "Лосось филе" #35c811e501c6 по продажам за день, что получится?
Расход продуктов по продажам -> /resto/api/reports/productExpense
Вызываем соответствующий метод iikoServer API: /resto/api/reports/productExpense?dateFrom=21.08.2021&dateTo=21.08.2021&hourFrom=-1&hourTo=-1&department=...8a03891ceb68
Указать конкретный идентификатор элемента номенклатуры нельзя, Айко возвращает расход для всех продуктов:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <dayDishValues> <dayDishValue> <date>21.08.2021</date> <productName>Кунжут белый</productName> <productId>...35c811e501c2</productId> <value>0.388</value> </dayDishValue> <dayDishValue> <date>21.08.2021</date> <productName>Лосось филе</productName> <productId>...35c811e501c6</productId> <value>16.524</value> </dayDishValue> ... </dayDishValues>dayDishValues>
Отлично! Видно, что указанная точка доставки реализовала 16.524 кг товара "Лосось филе" #35c811e501c6 за день 21 августа 2021 года.
Что плохо? В списке нет заготовок, только товары (продукты). Разбить расход по часам сразу нельзя, нужно для каждого часа, для каждой точки доставки делать отдельный запрос. У Клиента один запрос в арендованное облако iikoCloud занимает около 30 секунд, не подходит такое решение. Идём дальше.
2 вариант. Вхождение товара в блюдо
Попробуем узнать вхождение товара "Лосось филе" #35c811e501c6 в блюда "Маки с лососем", "Филадельфия с лососем" и "Сет для двоих". Вдруг Айко сразу выдаст нам нужный ответ?
Отчет о вхождении товара в блюдо -> /resto/api/reports/ingredientEntry
Вызываем соответствующий метод iikoServer API: /resto/api/reports/ingredientEntry?date=21.08.2021&product=...35c811e501c6&includeSubtree=false&department=...8a03891ceb68 и получаем ответ:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ingredientEntryDtoes> <item> <amountInMainUnit>1.299</amountInMainUnit> <unit>кг</unit> <treeLevel>1</treeLevel> <name>Лосось филе очищенное ПФ</name> <sourceProduct> <id>66e1ee4f2fcc</id> <name>Лосось филе очищенное ПФ</name> <type>PREPARED</type> </sourceProduct> </item> </ingredientEntryDtoes>
Айко отвечает нам: товар "Лосось филе" входит в состав другого элемента номенклатуры — заготовки (type = PREPARED) "Лосось филе очищенное ПФ". Расчета до блюд нет. Значит, нет прямого ответа на наш вопрос? Айко этим методом выдает вхождения только "первого уровня" в дереве технологических карт.
Стоп. У метода есть аргумент includeSubtree (включать ли в отчет строки поддеревьев, по умолчанию false), пробуем задать = true:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ingredientEntryDtoes> <item> <amountInMeasureUnit>1.299</amountInMeasureUnit> <treeLevel>1</treeLevel> <name>Лосось филе очищенное ПФ</name> <sourceProduct> <id>66e1ee4f2fcc</id> <name>Лосось филе очищенное ПФ</name> <type>PREPARED</type> </sourceProduct> </item> <item> <amountInMeasureUnit>0.064950000</amountInMeasureUnit> <treeLevel>2</treeLevel> <name>Маки с лососем</name> <sourceProduct> <id>35c811e50188</id> <name>Маки с лососем</name> <type>DISH</type> </sourceProduct> </item> <item> <amountInMeasureUnit>0.129900</amountInMeasureUnit> <treeLevel>2</treeLevel> <name>Филадельфия с лососем</name> <sourceProduct> <id>35c811e501a7</id> <name>Филадельфия с лососем</name> <type>DISH</type> </sourceProduct> </item> <item> <amountInMeasureUnit>0.064950000</amountInMeasureUnit> <treeLevel>3</treeLevel> <name>Сет для двоих</name> <parentId>83f61602ac51</parentId> <sourceProduct> <id>2d2536539600</id> <name>Сет для двоих</name> <type>DISH</type> </sourceProduct> </item> <item> <amountInMeasureUnit>0.129900000</amountInMeasureUnit> <treeLevel>3</treeLevel> <name>Сет для двоих</name> <parentId>83f61602ad42</parentId> <sourceProduct> <id>2d2536539600</id> <name>Сет для двоих</name> <type>DISH</type> </sourceProduct> </item> </ingredientEntryDtoes>
То, что нужно. Уровень вложенности возвращается в поле <treeLevel>. Обращаем внимание на два последних элемента <item> — они отличаются атрибутом <parentId> (Павел, спасибо за подсказку!) Это значит, что для блюда "Сет для двоих" есть несколько входящих в него элементов номенклатуры, каждый из которых содержит товар "Лосось филе". И чтобы найти итоговое вхождение товара "Лосось филе" в блюдо "Сет для двоих", нужно учесть все эти отдельные вхождения.
Рабочее решение. Финальный алгоритм решения задачи:
1. Заранее строим справочник вхождений исходного товара/заготовки во все блюда ресторана.
2. Строим отчет о продажах за день.
3. Зная количество проданных блюд за день и умножая на значения вхождений из справочника, получаем итоговый ответ на вопрос менеджера.
3 вариант. Получение технологических карт
Внешний разработчик может выгрузить через iikoServer API все действующие и удаленные технологические карты.
https://ru.iiko.help/articles/#!api-documentations/recipes
Важное замечание из официальной документации:
Технологические карты (рецепты) в iiko строго привязаны к элементам номенклатуры (блюдам, модификаторам, заготовкам) и датам: на каждый учетный день элементу номенклатуры может быть сопоставлено не более одной технологической карты. Единственная сопоставленная карта должна задавать метод списания (целиком/по ингредиентам) и состав+количество ингредиентов для всех действующих и удаленных подразделений, размеров блюд.
Ингредиентом блюда, модификатора, заготовки может быть заготовка, имеющая свою собственную технологическую карту. Таким образом, техкарты образуют деревья.
Решить поставленную менеджером задачу можно и таким способом: выгрузить дерево технологических карт, рассчитать вручную вхождения заданного товара во все блюда из меню ресторана, по отчету о продажах за день найти итоговый ответ.
Но подробнее о технологических картах в другой раз 😉
Отчет Семёна Фудова
У Сёмена Фудова есть такой отчет — "Расход заготовок", в котором есть ответ на вопрос: "Сколько-таки лосося было израсходовано за день?" С разбивкой по отдельным точкам доставки, по часам.
Если заинтересовались в таком отчете для своей службы доставки — пишите на почту hello@fudov.ru, подключим.