Расход товаров и заготовок в Айко с учетом вложенных технологических карт
Задача: рассчитать в Айко расход товара (скажем, "Лосось филе") за день. При условии, что в ресторане заданы вложенные технологические карты и в меню есть составные блюда.
Здесь и далее используются реальные данные реального Клиента, идентификаторы и названия товаров/заготовок/блюд частично "урезаны" для сохранения конфиденциальности.
Дано
В меню ресторана есть три блюда:
- Ролл "Маки с лососем" #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, подключим.