Этот текст написан в Сообществе, в нем сохранены авторский стиль и орфография
К нам с командой обратилась сеть заведений «ВКУСНО 55». На тот момент у компании было больше 80 точек и несколько брендов, включая Coffee Anytime, Hot и «Шампур». Нужно было автоматизировать сбор заявок на продукты и убрать из этого процесса как можно больше ручной работы.
Рассказываем, что из этого получилось.
О Сообщнике Про
SEO в диджитал-агентстве. Специализируюсь на комплексном продвижении: от тех. аудитов и семантики до стратегий роста. Провожу кластеризацию, готовлю ТЗ и линкбилдинг.
Это новый раздел Журнала, где можно пройти верификацию и вести свой профессиональный блог.
С чего все начиналось
Когда у компании несколько заведений, часть рабочих процессов вполне можно вести в Excel, мессенджерах и по телефону. Пока точек немного, это не кажется большой проблемой.
По сути, нам предстояло сделать приложение для общепита, которое должно было заменить сразу несколько привычных инструментов: телефон, бумажные заявки и электронные таблицы.
Но у «ВКУСНО 55» заведений стало больше 80. И в какой-то момент стало понятно, что собирать заявки на продукты по привычной схеме дальше будет затруднительно.
Сотрудник одной точки передает заявку оператору, оператор переносит ее в Excel, собирает данные с других точек, а потом вручную переносит все это в r_keeper StoreHouse.
Получается длинная цепочка:
Точка → звонок или бумажная заявка → оператор → Excel → StoreHouse → накладная.
Мы не исключали человеческий фактор, поэтому на каждом этапе есть риск ошибки и, как следствие, потеря времени.
Перед нами стояла сложная задача: разобраться в цепочке процессов и автоматизировать ее. Хотя сначала она казалась довольно простой: сделать веб-приложение для заявок. Однако по ходу проекта выяснилось, что одной формы здесь будет недостаточно.
Нужно было автоматизировать весь путь заявки, от заполнения сотрудником конкретной точки до формирования документов в складской системе.
Причем автоматизировать нужно было сразу несколько связанных процессов: работу с торговыми точками, создание шаблонов, подачу и корректировку заявок, консолидацию данных, формирование накладных и синхронизацию справочников с StoreHouse.
Что было не так с прежним процессом
Представим обычный день.
Сотруднику Coffee Anytime нужно заказать продукты. Он составляет список и передает его оператору. Оператор получает такие же списки от других заведений, сводит их в таблицу, проверяет и переносит данные дальше.
При 5–10 точках это уже рутинная работа. При 80+ она превращается в отдельный производственный процесс.
У старой схемы было несколько очевидных проблем.
Во-первых, много ручной работы.
Одни и те же данные несколько раз переносились между разными форматами. Сотрудник написал количество товара, оператор перенес его в Excel, затем данные еще раз попали в складскую программу.
Во-вторых, человеческий фактор.
Достаточно ошибиться в одной цифре, и на точку приедет другое количество товара. Причем ошибку можно было допустить на любом этапе.
В-третьих, сроки.
У заявок были дедлайны. Если сотрудник не успевал отправить данные, оператор мог узнать об этом уже после установленного времени.
Поэтому мы решили автоматизировать весь процесс.
Как собрали систему
Когда определились с задачами, нужно было понять, как все это связать между собой. В итоге выбрали монолитную SPA-архитектуру: серверная часть отвечает за бизнес-логику и работу с данными, React формирует интерфейс, а через API приложение обменивается информацией с r_keeper StoreHouse.

Для интерфейса использовали React и Inertia.js. Такой вариант позволил получить привычную динамику одностраничного приложения, при этом не пришлось отдельно строить API для фронтенда.
А дальше уже перешли к пользователям и их ролям.
Сначала определили, кто будет работать с системой
Прежде чем продумывать интерфейс, мы посмотрели на сам процесс и определили, кто в нем участвует. У каждого своя задача, поэтому делать одинаковый набор функций для всех пользователей не имело смысла.
Получилось четыре роли:
- сотрудник торговой точки;
- оператор;
- менеджер;
- администратор.
Сотрудник видит только свою точку и работает со своими заявками. Оператор видит заявки всех точек, создает шаблоны, контролирует их и отправляет документы в StoreHouse. Менеджеру нужен в основном просмотр: заявки, архив и сводные данные доступны, но редактировать их нельзя. Администратор управляет пользователями и настройками системы.
Нам не хотелось делать интерфейс, где сотрудник видит десятки функций, которыми ему никогда не придется пользоваться. Поэтому каждому пользователю оставили только те возможности, которые нужны для его работы.
Оператор управляет шаблонами и заявками, сотрудник точки заполняет свою заявку, менеджер просматривает данные.
Торговые сети и точки
Дальше нужно было разобраться с самой структурой сети. В системе несколько брендов, а внутри каждого есть свои торговые точки.

Оператор может работать сразу с несколькими сетями и видеть их точки в одном интерфейсе.

При добавлении точки указываются ее основные данные и соответствие в StoreHouse. Это связывание нужно для дальнейшей передачи заявок в складскую систему.

Для каждой точки можно назначить нужный шаблон заявки. Поэтому сотрудник после входа сразу работает со своей заявкой и не сталкивается с настройками, которые ему не нужны.

Получилась простая логика: оператор управляет структурой и настройками, а сотрудник работает только с тем, что относится к его точке.
Теперь о самой заявке
После того как определились с пользователями и структурой точек, перешли к главному элементу системы. Заявка должна была быть привычной для сотрудников, поэтому заказчик хотел интерфейс, похожий на Excel.
А вот с реализацией начались нюансы.
В таблице нужно было:
- искать товары по названию и коду;
- указывать количество;
- работать с дробными значениями;
- проверять введенные данные;
- менять ширину колонок;
- группировать строки;
- автоматически сохранять изменения;
- ограничивать возможность редактирования в зависимости от роли пользователя.
Мы взяли за основу Quill.js и плагин для работы с таблицами. Готовый функционал не закрывал необходимые задачи, поэтому часть возможностей пришлось серьезно доработать.
Например, сотрудник точки должен видеть готовую структуру заявки и заполнять определенные колонки. Оператор при этом должен иметь возможность менять сам шаблон.
Отдельно сделали поиск товаров прямо внутри ячейки. Можно начать вводить название или код, и система предлагает подходящую позицию.

Еще работали с тем, как редактор хранит данные. Quill использует формат Delta, JSON-структуру, в которой описываются операции с содержимым. Для дальнейшей работы нам нужно было получать из нее обычные структурированные данные заявки.
В итоге написали собственный обработчик, который разбирает содержимое таблицы и передает данные дальше.
На этом этапе стало понятно, что задача «сделать форму для заявок» довольно быстро превратилась в полноценное приложение.
Шаблон заявки создается один раз
Следующая проблема была в том, что заявки у разных точек могут отличаться.
Например, одна точка работает с одним набором товаров, другая с другим. Где-то используется определенный тип заявки, где-то другой график подачи.
Создавать такие таблицы вручную каждый раз было бы странно.
Поэтому мы сделали шаблоны.
Оператор один раз настраивает структуру заявки, указывает товары, единицы измерения, дни использования, сроки корректировки и другие параметры. Затем шаблон можно привязать к нужным точкам.
У шаблона есть и дополнительные параметры: время приема заявки, период дневной и вечерней корректировки, а также смещение даты отгрузки. Причем для разных дней недели можно задать разные значения.

Если нужен похожий вариант, существующий шаблон можно скопировать и немного изменить.
Отдельно задали ограничения на количество товаров. Например, если сотрудник случайно вводит слишком большое значение, система предупреждает его еще при заполнении.

У одной заявки может быть две версии за день
Здесь появился еще один интересный сценарий.
Заявку нельзя было считать окончательной сразу после первого заполнения.
У сотрудников есть дневная и вечерняя корректировка. Днем они указывают основные объемы, а после установленного времени могут скорректировать некоторые значения.
Система сама понимает, какая сейчас фаза, и блокирует или открывает нужные колонки.
После окончательной отправки сотрудник уже не может изменить заявку самостоятельно.
Для точек, которые не работают в определенные дни, предусмотрели еще один сценарий. Заявку можно создать заранее и запланировать ее отправку. Система сама активирует ее в нужную дату.

Но нам было важно не потерять историю.
Поэтому каждое сохранение создает новую версию. Оператор может просмотреть предыдущие варианты и понять, что именно изменилось.

Это особенно полезно, когда нужно разобраться с расхождением: например, почему сначала было указано 10 единиц товара, а потом стало 15.
Вместо предположений можно просто открыть историю изменений.
Как оператор видит заявки всех точек
Отдельно мы сделали список заявок.
По нему оператор может быстро посмотреть, какие заявки созданы, по каким точкам они пришли и прошла ли корректировка.

Для статусов использовали простые визуальные маркеры. Желтый показывает, что заявка создана, зеленый, что оператор ее уже просмотрел.
Отдельно сделали архив.
В нем находятся отправленные в StoreHouse заявки. Их можно открыть, посмотреть и распечатать.

Для поиска добавили фильтры по типу заказа и времени подачи.
А теперь к главной части операторского интерфейса.
По сути, это большая сводная таблица, где оператор видит заявки сразу всех точек сети.
По вертикали находятся товары, по горизонтали точки, а в ячейках указано количество.
То есть вместо десятков отдельных заявок оператор получает одну общую картину.

Дата здесь тоже не всегда одинаковая. У разных точек одной сети она может отличаться из-за настроек отгрузки в шаблоне. Поэтому система учитывает этот параметр при формировании сводной таблицы.
Есть и отдельная консолидация для напитков, поскольку для этой категории используется собственная логика группировки.
Еще один момент: оператор может менять количество прямо из сводной таблицы.
При изменении количества система не стирает исходную заявку, а создает новую версию.

По клику на торговую точку можно открыть заявку для печати. Отдельно предусмотрели пакетную печать, когда нужно сформировать документы сразу по нескольким точкам.

Но на этом автоматизация не заканчивается
Можно сделать удобную систему заявок, но если после этого оператору придется вручную переносить все данные в складскую программу, половина проблемы останется.
Поэтому следующим этапом стала интеграция с r_keeper StoreHouse.
Заявка должна была превратиться в реальный складской документ.
Мы настроили передачу данных из приложения в StoreHouse и предусмотрели два основных сценария: формирование накладных и документов комплектации для соответствующих позиций.
Накладная используется для стандартной передачи товара от поставщика к точке. Комплектация нужна для позиций, которые состоят из нескольких компонентов, например полуфабрикатов или сборных блюд.
Здесь была еще одна техническая особенность: отправлять все документы одновременно нельзя.
Поэтому сделали очередь.
Оператор нажимает кнопку отправки, документы уходят на обработку, а сам оператор может продолжать работать. Не нужно сидеть перед экраном и ждать, пока система закончит.
После завершения приходит уведомление.
В очереди документы обрабатываются последовательно. Это помогает избежать конфликтов при одновременной работе с StoreHouse и снижает нагрузку на складскую систему.
Данные о товарах тоже должны быть актуальными
Еще одна вещь, которую легко забыть при автоматизации — справочники.
В системе должны совпадать товары, категории, цеха и единицы измерения с данными в StoreHouse.
Иначе получится странная ситуация: сотрудник выбирает товар из списка, который уже устарел, а система потом не может корректно сформировать документ.
Поэтому мы настроили регулярную синхронизацию.
Каждый день система получает из StoreHouse информацию о цехах, группах товаров, категориях, самих товарах и единицах измерения. Устаревшие позиции, которых больше нет в складской системе, удаляются из актуального справочника приложения.

Есть и ручной запуск синхронизации, предусмотренный на случай, если оператору нужно обновить данные вне обычного расписания.
При этом повторно запустить импорт во время уже выполняющейся синхронизации нельзя. Это защищает систему от нескольких параллельных загрузок одних и тех же данных.
Уведомления тоже автоматизировали
Когда сотрудник отправляет заявку, оператору не нужно постоянно обновлять страницу и проверять, не появилось ли что-то новое. В системе есть уведомления о поступивших заявках.
Операторы могут сами выбрать, по каким торговым сетям и типам заявок хотят получать уведомления. Информация на главной странице обновляется автоматически.
Есть и общая логика просмотра: если один оператор уже открыл заявку, уведомление о ней исчезает у остальных.
А если у точки сломался компьютер?
Во время разработки мы старались учитывать и не идеальные сценарии.
Например, сотрудник должен отправить заявку, но рабочий компьютер на точке сломался.
В такой ситуации не хотелось возвращаться к звонкам и бумагам.
Поэтому сделали временный доступ по одноразовой ссылке. Администратор может сгенерировать ее и передать сотруднику.
Ссылка используется один раз, а сессия действует ограниченное время.
Временный доступ работает 24 часа. После первого использования токен уничтожается, а администратор в любой момент может отозвать активную ссылку.
То есть сотруднику не приходится передавать обычный логин и пароль через мессенджер.
Еще одна задача появилась уже после запуска
Штатных возможностей StoreHouse оказалось недостаточно для пакетной печати накладных в нужном формате. Поэтому эту часть мы тоже реализовали на стороне веб-приложения для общепита.
Оператор выбирает нужные документы, система получает данные из StoreHouse, формирует единый формат и отправляет его на печать.
Это кажется небольшой функцией, но при большом количестве точек такие операции быстро превращаются в отдельную рутину.
И напоследок: документация
После разработки нужно было оставить систему в состоянии, с которым смогут работать другие разработчики. Поэтому мы отдельно подготовили документацию по проекту.
React-компоненты описали через JSDoc, PHP-код документировали через DocBlock, а на их основе сформировали HTML-документацию. В ней есть структура проекта, описание компонентов, маршрутов, миграций и процесса развертывания.

Отдельно можно посмотреть документацию по контроллерам и другим частям приложения.

Что в итоге изменилось
До проекта схема выглядела примерно так:
Сотрудник точки → телефон/бумага → оператор → Excel → StoreHouse.
После:
Сотрудник точки → веб-приложение → проверка → консолидация → StoreHouse.
В результате нам удалось автоматизировать около 80% ручной работы, упростить контроль более чем 80 торговых точек и обеспечить обработку 250+ заявок в дневные и вечерние периоды.
Мы начинали с задачи «сделать систему для заявок», а в итоге автоматизировали целый бизнес-процесс.











