Как стать автором
Обновить
KISLOROD
Создаем цифровые продукты для e-commerce

Вкалывают роботы, а не человек: как мы разработали ТГ-бота, который в 4 раза ускорил проведение маркетинговых акций

Уровень сложностиСредний
Время на прочтение24 мин
Количество просмотров1.8K

Привет, хабровчане! Я Алиса — тимлид в e-commerce агентстве KISLOROD. Хочу рассказать об интересном кейсе по разработке ТГ-бота, который мы интегрировали с сайтом на 1С-Битрикс.

Бот забрал на себя до 70% механической работы и рутинных операций менеджеров со стороны клиента, а покупателям упростил регистрацию в акциях в несколько раз.

Собственно, ботом сейчас никого не удивить, но наш бот необычный — это узкоспециализированный ТГ-бот для проведения маркетинговых мероприятий. Кейс находится под NDA, поэтому мы не можем раскрыть всю информацию, но самое интересное — расскажем.

Про нашу часть работы мы написали максимально подробно: описали алгоритмы, механику обработки команд и привели примеры кода.

Откуда растут ноги у бота?

Клиент — крупная ювелирная компания, у которой десятки салонов по всей стране, а кроме того, она — поставщик для других ювелирных сетей, которым продает украшения оптом.

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

Изначально, команда клиента проводила все маркетинговые мероприятия через сайт, но, по данным аналитики, пользователи часто сталкивались с проблемами — был высокий процент отказов, покупатели неохотно вовлекались или могли бросить оформление на полпути. 

Ну и самый частый сценарий — людям было просто лень регистрироваться на отдельном сайте, хранить чеки, заполнять поля и вот это вот все. А продавцы в реальных салонах сталкивались с тем, что им нужно тратить достаточно много времени для заполнения данных на сайте.

В общем, никто не хотел умирать работать больше обычного.

Итого у команды бренда было три глобальные потребности:

  1. Передать всю рутинную и механическую работу в бота = автоматизировать процессы регистрации, заполнения и проверки данных и пр.

  2. Дать партнерам работающий инструмент, который снимет головную боль с проведением этих акций.

  3. Упростить жизнь покупателям, чтобы оно там само как-то работало, баллы начислялись, скидки применялись, подарочки получались.

Платформой для бота выбрали, конечно же, Телеграм:

  • это самый популярный мессенджер — есть почти у каждого;

  • он всегда под рукой в смартфоне — не надо ничего устанавливать или идти на сайт;

  • это удобненько для разработчиков — в ТГ уже есть Бот-батя, который создает ботов, раздает токены и API.

Далее немного о том, как проектировали бота вместе с клиентом.

Обсуждение и проектирование

Разработка и старт бота планировались под запуск конкретного маркетингового мероприятия. Это была закрытая акция только для избранных ювелирных сетей и лучших продавцов.

Поэтому надо было обеспечить:

  • корректную и бесперебойную работу бота;

  • конфиденциальность, безопасность и хранение данных;

  • ограниченный доступ для отдельных продавцов и ювелирных сетей.

Глобальная задача на будущее — обеспечить покупателям положительный клиентский опыт. То есть дарить радость от покупки, а не раздражение :) 

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

От клиента мы получили алгоритм работы бота — на нас ложилась реализация, разработка и техническое обеспечение.

В итоге было решено разработать два бота: один для продавцов, второй для покупателей, которые будут работать как с офлайн-, так и с онлайн-точками и немного отличаться по функциональности.

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

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

Сценарии и алгоритмы работы

Сценарии для ботов были разработаны так, чтобы их можно было использовать в различных маркетинговых акциях.

  • Бот покупателей — регистрирует покупки и уникальные штрихкоды, которые дают право на участие в акции.

  • Бот продавцов — регистрирует продажи и штрихкоды и упрощает работу с покупателями в рамках проведения акции.

Например, партнерская сеть ювелирных магазинов проводит акцию:

  • «Купите золотое кольцо в марте и получите 30% скидку на следующую покупку в апреле».

Посетители салонов и интернет-магазина после покупки получают штрихкод, регистрируют его через бота покупателей и получают уникальный ID участника. А уже при следующей покупке могут воспользоваться скидкой. 

Также с помощью такого бота можно проводить опросы, начислять баллы и бонусы, разыгрывать призы и делать специальные предложения.

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

В итоге маркетинговый отдел получает данные по продажам и результатам акции, что дает возможность оценивать эффективность мероприятий и персонализировать будущие предложения.

Таким образом, ТГ-боты — это гибкий инструмент для проведения различных маркетинговых акций, который может использоваться неоднократно.

Алгоритм бота для покупателей

Задачи — сохранение и проверка штрих-кодов и фотографий чеков.

  1. Покупатель заходит в бота и видит ссылки на сайт и правила акции.

  2. Получает приветственное сообщение с краткой инструкцией по работе с ботом.

  3. Запускает бота кнопкой «Старт».

  4. Вводит один штрихкод.

  5. Штрихкод либо проходит, либо не проходит проверку.

  6. Покупатель может ввести другие штрихкоды либо закончить введение данных.

  7. Вводит свои ФИО и телефон.

  8. Прикрепляет фотографию чека.

  9. Далее может закончить операцию.

  10. Либо добавить новую покупку и повторить схему.

  11. Получает сообщение «Вы добавили» продажу.

На этом сеанс работы с ботом считается завершенным.

Алгоритм бота для продавцов

Задачи — фиксация продаж и их статистика, сбор и управление данными.

  1. Продавец заходит в бота и видит ссылки на сайт и правила акции.

  2. Получает приветственное сообщение с краткой инструкцией по работе с ботом.

  3. Запускает бота кнопкой «Старт».

  4. Добавляет один или несколько штрихкодов.

  5. Штрихкод либо проходит, либо не проходит проверку.

  6. Продавец может ввести другие штрихкоды либо закончить введение данных.

  7. Добавляет телефон.

  8. Вводит ФИО.

  9. Указывает название ювелирной сети.

  10. Вводит сумму продажи.

  11. Прикрепляет фотографию чека.

  12. Получает сообщение «Вы добавили» продажу.

На этом сеанс работы с ботом считается завершенным.

Собственно создание ТГ-бота

Мы начали с создания ботов в @BotFather для получения уникальных API-токенов для каждого из них. Эти токены были сохранены в конфигурационных файлах сайта, так как они необходимы для аутентификации при обращении к API Telegram. 

Далее настроили вебхуки, что обеспечило мгновенное получение обновлений от Telegram и позволило боту реагировать на действия пользователей в реальном времени.

Мы разработали скрипты для обработки сообщений и команд с учетом множества вариантов ответов, чтобы обеспечить гибкость и адаптивность взаимодействия с пользователями.

Подготовили детальную структуру вопросов и ответов, которая формирует алгоритм действий клиентов. Важно было создать интуитивно понятный интерфейс, поэтому в бот были добавлены визуальные кнопки, которые упрощают навигацию и выбор опций для пользователей.

В связи с тем, что функциональные возможности обоих ботов имеют много общего, мы разработали служебный класс, который инкапсулирует логику обработки запросов и взаимодействия с API Telegram. Этот класс отвечает за прием и обработку данных от пользователей, а также за сохранение информации в базе данных. Такой подход обеспечивает повторное использование кода и упрощает дальнейшую поддержку и развитие ботов.

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

Валидация данных стала важной частью логики бота и позволила эффективно обрабатывать запросы и предоставлять пользователям актуальную информацию.

Далее расскажем о каждом этапе подробнее.

Логика работы

Оба бота работают по схожим принципам, но немного отличаются по функциям.

Механика бота покупателя

Действие пользователя

Результат

Открытие бота

Ссылка на страницу акции и правила для просмотра или скачивания в PDF

Старт

Запуск бота/Приветственное сообщение

Добавление продажи

Старт алгоритма

Введение штрихкода

Отправка информации боту

Отправление штрихкода

Проверка корректности и добавление в таблицу

Добавление телефона

Отправка информации 

Заполнение ФИО

Отправка информации

Прикрепление фотографии чека

Отправка информации 

Завершение процесса

Сообщение об успешном завершении

Закрытие бота/Новый цикл

Завершение или повторный старт

Схема работы бота покупателя
Схема работы бота покупателя

Механика бота продавца

Данный бот дает больше возможностей:

  • можно добавлять один или несколько штрихкодов;

  • необходимо вводить имя ювелирной сети и сумму продажи.

Действие пользователя

Результат

Открытие бота

Ссылка на страницу акции и правила для просмотра или скачивания в PDF

Старт

Запуск бота/Приветственное сообщение

Добавление продажи

Старт алгоритма

Введение штрихкода

Добавление нескольких штрихкодов/Отправка информации боту

Отправление штрихкода

Проверка корректности и добавление в таблицу

Добавление телефона

Отправка информации 

Заполнение ФИО

Отправка информации

Введение имени ювелирной сети

Отправка информации 

Введение суммы продажи

Отправка информации 

Прикрепление фотографии чека

Отправка информации 

Завершение процесса

Сообщение об успешном завершении

Закрытие бота/Новый цикл

Завершение или повторный старт

Схема работы бота продавца
Схема работы бота продавца

После завершения процесса, пользователь получает финальное уведомление.

Завершение работы бота
Завершение работы бота

Добавление продаж в таблицу

Боты отправляют все продажи в специальную таблицу в Битрикс.

Процесс выглядит так: 

  • При регистрации, информация о продаже добавляется в таблицу. 

  • Если продавец вводит штрихкоды, а затем временно покидает процесс, в течение короткого времени он может продолжить с того места, где остановился.

  • Но если он вернется на следующий день, то это будет считаться новой регистрацией.

  • При нажатии кнопки «Добавить продажу» появляется возможность «Ввести штрихкод». 

  • При этом продавец может добавлять любое количество кодов и завершить процесс в любой момент.

  • Далее необходимо добавить телефон, ФИО, данные о продаже и фото чека.

Когда процесс завершен, все данные добавляются в специальную таблицу.

Как Битрикс проверяет корректность данных

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

Таблица ранее выпущенных штрихкодов
Таблица ранее выпущенных штрихкодов
  • Если введенный штрихкод не найден или находится в стоп-листе, пользователь получит сообщение, что данный код не может участвовать в акции.

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

Когда все корректные штрихкоды введены, пользователь нажимает кнопку «Завершить ввод штрихкодов», после чего бот предлагает ввести телефон, ФИО, имя клиента, сумму продажи и прикрепить фото чека.

В итоге система отправляет корректные данные в Битрикс. Здесь имеется таблица с данными пользователей и их действиями, которая очищается перед каждой новой акцией. 

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

Таблица штрихкодов покупателей
Таблица штрихкодов покупателей
Таблица штрихкодов по данным от продавцов 
Таблица штрихкодов по данным от продавцов 

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

Как и зачем мониторить продажи

Группировка продаж нужна, чтобы менеджерам было проще отслеживать статистику продаж. Раз в неделю они выгружают данные из таблицы для анализа продаж. 

За каждые 25 000 ₽, которые продавец генерирует в продажах, он получает 500 ₽ на телефон через Сбербанк. Это нужно, чтобы учитывать не только единичные сделки на сумму 25 000 ₽, но и общее количество регистраций.

Важно отметить, что один и тот же человек может иметь несколько регистраций. Например, он может ввести данные только для одной продажи, прикрепив один штрихкод и один чек. Это демонстрирует работу системы на практике. 

Менеджер проверяет введенные данные и сверяет их с базой для обеспечения минимального контроля. В Битрикс есть таблица, из которой менеджер может скачивать данные и следить за выплатами в Excel — это сделано для удобства группировки информации. Общая таблица включает участников, которые регистрируются как через сайт, так и через бота.

Далее немного технической информации об архитектуре интеграции.

Архитектура интеграции с Битрикс

Скрытый текст

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

Для реализации ТГ-ботов мы выбрали архитектурное решение на стандартном API Telegram, который доступен по адресу core.tlgr.org/bots/api.

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

А обращение к API Telegram было реализовано посредством стандартной библиотеки CURL, которая используется для получения и передачи данных через такие протоколы, как HTTP, FTP, HTTPS, и методами GET и POST, которые используются в API Telegram. 

На мой взгляд API Telegram имеет интуитивно понятную структуру URL для отправки запросов.

Вот пример URL для взаимодействия с ботом:

Где {token} — это уникальный ключ, получаемый при создании бота, а {method} — это метод запроса, с помощью которого мы можем получать или отправлять определенные данные. В зависимости от названия метода, будут выполняться различные действия.

Существует два вида взаимодействия с ботом через API: первый — это от клиента к серверу, а второй — от сервера к клиенту. Клиентом в данном случае является сайт на 1С-Битрикс, а сервером — бот в Telegram.

API-запрос — это способ общения с программой посредством отправки данных от клиента к серверу. Он позволяет клиенту инициировать действия, такие как: отправка сообщений, получение информации или выполнение различных команд, при взаимодействии с ботом.

Hooks (Хуки) — это способ общения с программой посредством отправки данных от сервера к клиенту. Каждый раз, когда пользователи пишут боту, данные о сообщениях отправляются на указанный скрипт, где происходит обработка сообщения и формирование ответа. Это позволяет боту реагировать на действия пользователей в реальном времени.

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

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

Для вебхуков мы настроили соответствующие скрипты на стороне сайта, которые принимают входящие запросы от Telegram и обрабатывают их в соответствии с заданной логикой. Это позволило обеспечить мгновенную реакцию на действия пользователей и гарантировать, что данные о продажах и других действиях будут своевременно обновляться в системе.

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

Механизм работы и обмена данными с 1С-Битрикс

Привязка вебхука и проверка — спойлер→

Чтобы бот работал быстро, без зависаний и ошибок мы выбрали метод работы с вебхуками. Поскольку сайт на 1С-Битрикс уже работал, то скрипты для ботов мы разработали без проблем.

Затем создали скрипты, которые обрабатывают запросы от ботов. Скрипты доступны по следующим URL: 

С помощью API Telegram мы привязали эти адреса для вызова вебхуков.

Для регистрации вебхука необходимо отправить запрос с использованием метода setWebhook(), в котором в качестве параметра url передается ссылка на скрипт-обработчик. 

Запрос можно выполнить любым удобным способом. Мы использовали Postman, однако такой запрос можно отправить даже через браузер. 

Запрос имеет следующий вид:

https://api.telegram.org/bot{token}/setWebhook?url=https://mysite.com/local/tools/federalBuyerBot.php

На этом, собственно, интеграция завершена, осталось лишь проверить привязку вебхука.

Запрос должен отдавать следующий ответ:

{
  "ok": true,
  "result": true,
  "description": "Webhook was set"
}

Если все совпадает, то адрес вебхука привязан успешно.

Для бота покупателя провели ровно те же манипуляции.

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

Данные, которые принимает скрипт

Вебхуки работают так, что при обращении к боту происходит отправка запроса к скрипту. Скрипт принимает запросы в формате JSON. Соответственно, при получении запроса скрипт должен произвести действия и отправить ответ в бота. 

Пример такого запроса:

{
  "update_id": 11372597,
  "message": {
    "message_id": 3,
    "from": {
      "id": 1095554896,
      "is_bot": 1,
      "first_name": "Иван",
      "last_name": "Иванов",
      "username": "ivan_ivanoff",
      "language_code": "ru",
      "is_premium": 1
    },
    "chat": {
      "id": 1095554896,
      "first_name": "Иван",
      "last_name": "Иванов",
      "username": "ivan_ivanoff",
      "type": "private"
    },
    "date": 1732260152,
    "text": "Добавить покупку"
  }
}

При получении такого запроса скрипт проверяет, обрабатывает и сохраняет данные, а также формирует ответ. Для этого скрипт преобразует JSON в массив, и анализирует данные, которые приходят в сообщении из бота.

$data = file_get_contents('php://input');
$data = json_decode($data, true);

Для обмена сообщениями мы используем данные из приходящего массива. В частности, нам нужен параметр id из массива message[from]. Этот параметр указывает идентификатор чата, с которым мы производим обмен сообщениями.

Обработка данных и состояния бота

Скрытый текст

Бот способен взаимодействовать с несколькими пользователями и находиться в различных состояниях, таких как: 

  • ввод чеков;

  • ввод данных клиента;

  • отправка фотографий чеков.

Однако, поскольку Telegram-бот не сохраняет свои состояния, было необходимо реализовать функции для управления этими состояниями. 

Чтобы бот мог корректно определять, что он находится в режиме ввода заявки от конкретного пользователя, нам потребовалось сохранять и считывать состояния индивидуально для каждого пользователя.

Для этого мы разработали методы, которые сохраняют текущее состояние бота и извлекают его для конкретного пользователя.

Чтобы хранить эти состояния, мы создали на сервере директорию/upload/telegram/state/и дали ей права на запись. Состояния сохраняются в бинарных файлах, названия которых соответствуют chatId пользователей, и содержат информацию о последней выполненной команде.

Хранение текущих состояний бота
Хранение текущих состояний бота

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

Каждому пользователю будет соответствовать отдельный файл в директории /upload/telegram/data/ в который будут записываться введенные данные. Названия файлов могут быть аналогичны chatId пользователей — это упростит процесс идентификации и извлечения информации.

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

Получение и сохранение данных ботом
Получение и сохранение данных ботом

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

Кроме того, нам было важно предусмотреть механизмы для обработки ошибок и валидации данных на этапе их ввода. 

Если пользователь введет некорректные данные, бот должен уведомить его об этом и предложить повторить ввод. Таким образом, система становится более надежной и удобной для пользователей, уменьшая вероятность потери информации.

Проверка выпущенных штрихкодов
Проверка выпущенных штрихкодов
Проверка штрихокда на присутствие в стоп-листе
Проверка штрихокда на присутствие в стоп-листе

Отправка сообщений

Следующий этап разработки — создание метода для отправки сообщений. Для отправки сообщений в API Telegram мы использовали метод sendMessage(). Он способен обрабатывать и GET, и POST запросы, но мы будем использовать только POST-запросы для удобства при обмене большими сообщениями. 

Метод sendMessage() принимает три параметра:

  • chat_id — идентификатор чата;

  • parse_mode — режим обработки сообщений, в нашем случае это html;

  • text — собственно текст сообщения.

Кроме того, в соответствии с требованиями команды клиента, нам нужно было реализовать функциональность кнопок в Telegram-боте, используя стандартные возможности API Telegram. Для создания кнопок дополнительно в метод sendMessage() мы передаем параметр reply_markup, который содержит массив с данными кнопок.

API Telegram реализует три типа кнопок:

  1. Кнопки, которые прикреплены к сообщению — inline_keyboard.

  2. Кнопки, которые располагаются под строкой ввода сообщения, известные как клавиатура — keyboard.

  3. Кнопки командного меню, которые обычно расположены слева от строки ввода сообщения.

Нам необходимы кнопки, которые располагаются под строкой.

Пример использования кнопок в боте
Пример использования кнопок в боте

Для создания такого вида кнопок в метод sendMessage() в качестве параметра reply_markup мы передаем массив с настройками клавиатуры. 

Кроме того, нам нужно передать два дополнительных параметра:

Кроме того, нам нужно передать два дополнительных параметра:

  1. one_time_keyboard — скрывает клавиатуру после ее использования. 

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

По умолчанию, значение установлено в false. Нам нужно, чтобы клавиатура скрывалась, поэтому, мы устанавливаем данный параметр в true.

2. resize_keyboard — изменяет вертикальный размер клавиатуры для оптимального отображения, например, уменьшает размер при наличии только двух рядов кнопок. 

Значение по умолчанию — false, что означает, что пользовательская клавиатура всегда будет иметь ту же высоту, что и стандартная клавиатура приложения. Но нам нужно, чтобы клавиатура скрывалась, поэтому, мы устанавливаем данный параметр в true.

Структура данного массива в нашем случае выглядит следующим образом:

'reply_markup' => [
    'keyboard' => [
        [
              [
                  [
                      'text' => 'Ввести штрихкод (один или несколько)',
                      'callback_data' => '/barcodeEnter',
                  ]
              ],
              [
                  [
                      'text' => 'Ввести ещё штрихкод',
                      'callback_data' => '/barcodeMore',
                  ],
                  [
                      'text' => 'Закончить введение штрихкодов',
                      'callback_data' => '/barcodeEnd',
                  ]
              ]
        ],
        'one_time_keyboard' => true,
        'resize_keyboard' => true,
    ],
]

Результат вывода такой клавиатуры такой.

В результате работы метод для отправки сообщений на сайт выглядит так.

Получение фотографий

Скрытый текст

При отправке фотографии в скрипт приходит JSON, который содержит в себе информацию о файле, отправленном пользователем.

Вид данного JSON:

{
  "update_id": 11372597,
  "message": {
    "message_id": 6,
    "from": {
      "id": 1095554896,
      "is_bot": 1,
      "first_name": "Иван",
      "last_name": "Иванов",
      "username": "ivan_ivanoff",
      "language_code": "ru",
      "is_premium": 1
    },
    "chat": {
      "id": 1095554896,
      "first_name": "Иван",
      "last_name": "Иванов",
      "username": "ivan_ivanoff",
      "type": "private"
    },
    "date": 1659099213,
    "photo": [
      {
        "file_id": "AgACAgIAAxkBAAMqYuPYTHnTFqNQZ3DB5B-f_MovPOMAArm9MRud5CFLxgi3BP6dpsoBAAMCAANzAAMpBA",
        "file_unique_id": "AQADub0xG53kIUt4",
        "file_size": 1863,
        "width": 90,
        "height": 90
      },
      {
        "file_id": "AgACAgIAAxkBAAMqYuPYTHnTFqNQZ3DB5B-f_MovPOMAArm9MRud5CFLxgi3BP6dpsoBAAMCAANtAAMpBA",
        "file_unique_id": "AQADub0xG53kIUty",
        "file_size": 30064,
        "width": 320,
        "height": 320
      },
      {
        "file_id": "AgACAgIAAxkBAAMqYuPYTHnTFqNQZ3DB5B-f_MovPOMAArm9MRud5CFLxgi3BP6dpsoBAAMCAAN5AAMpBA",
        "file_unique_id": "AQADub0xG53kIUt-",
        "file_size": 133230,
        "width": 880,
        "height": 880
      },
      {
        "file_id": "AgACAgIAAxkBAAMqYuPYTHnTFqNQZ3DB5B-f_MovPOMAArm9MRud5CFLxgi3BP6dpsoBAAMCAAN4AAMpBA",
        "file_unique_id": "AQADub0xG53kIUt9",
        "file_size": 138716,
        "width": 800,
        "height": 800
      }
    ]
  }
}

Чтобы работать с этим JSON мы также преобразуем его в массив. В нем изображения содержатся в подразделе['message']['photo'].

Если же фотография отправляется в виде приложенного документа, то изображение располагается в ['message'][‘document’].Получение файла происходит при использовании параметра идентификатора файла file_id.

Далее, чтобы получить файлы в API Telegram, используется метод getFile(). Этот метод принимает параметр file_id, который указывает на идентификатор файла, полученный заранее. Данный метод возвращает внутренний URL файла, который мы преобразуем во внешний, и сохраняем файл на сервере в директории /upload/telegram/images/.

В результате работы, метод для получения и сохранения фотографий на сайт выглядит так:

public function getImage($fileId): string
{
    $getQuery = [
        'file_id' => $fileId
    ];

    $ch = curl_init('https://api.telegram.org/bot' . $this->token . '/getFile?' . http_build_query($getQuery));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_HEADER, false);

    $resultQuery = curl_exec($ch);
    curl_close($ch);

    $resultData = json_decode($resultQuery, true);
    if ($resultData['ok']) {
        $fileUrl = $resultData['result']['file_path'];
        $photoPathTG = 'https://api.telegram.org/file/bot' . $this->token . '/' . $fileUrl;
        $filePath = explode('/', $fileUrl);
        $newFilerPath = '/upload/telegram/images/' . date('Y_m_d_H_i_s') . '_' . $filePath[1];
        file_put_contents($_SERVER['DOCUMENT_ROOT'] . $newFilerPath, file_get_contents($photoPathTG));

        return 'https://test.com' . $newFilerPath;
    } else {
        return '';
    }
}

Механика обработки команд

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

Эта механика управляет состояниями бота и взаимодействием с пользователем в зависимости от введенных команд. Каждая команда обрабатывается отдельно, что позволяет гибко реагировать на действия пользователя и предоставлять необходимую информацию или услуги.

Если сообщение присутствует, то инициализируются данные:

if (!empty($data['message'])) {
	$buttons = [];
	$chatId = $data['message']['from']['id'];
	$userName = $data['message']['from']['username'];
	$firstName = $data['message']['from']['first_name'];
	$lastName = $data['message']['from']['last_name'];
	$image = $data['message']['photo'];
	$document = $data['message']['document'];
	$text = trim($data['message']['text']);
	$textArray = explode(" ", $text);

Создается пустой массив $buttons, который может использоваться для хранения массива для кнопок интерфейса.

Затем извлекаются различные данные о пользователе и сообщении:

  • chatId — уникальный идентификатор чата (пользователя), откуда пришло сообщение;

  • userName, firstName, lastName — информация о пользователе, включая его имя и фамилию;

  • image — массив фотографий, если они были отправлены;

  • document — информация о документе, если он был прикреплен к сообщению;

  • text — текст сообщения, очищенный от лишних пробелов с помощью функции trim();

  • textArray — массив слов, полученный путем разделения текста на отдельные слова с помощью функции explode().

После этого происходит получение данных пользователя и о состоянии бота:

  • $clientData = $telegram->getBotData($chatId)

  • $botStatus = $telegram->getBotState($chatId)

Чтобы получить информацию о пользователе и текущем состоянии бота, вызываем методы, которые описаны выше:

  • getBotData($chatId) — извлекает данные о пользователе (клиенте) по его идентификатору чата. Может включать информацию о предыдущих взаимодействиях пользователя с ботом.

  • getBotState($chatId) — возвращает текущее состояние бота для данного пользователя. Это может быть полезно для управления логикой взаимодействия с пользователем.

Логика обработки различных команд, отправленных пользователями в Telegram-бота, реализована при помощи конструкции switch. Она позволяет выполнять различные действия, которые зависят от значения переменной $text, содержащей текст сообщения от пользователя. 

Ниже перечислим основные команды, которые принимает бот.

Скрытый текст

Обработка команды /start

case '/start':
	$telegram->setBotData($chatId, []);
	$telegram->setBotState($chatId, 'start');
	$textReturn = "Добро пожаловать! Ссылка на сайт: https://t.me/Fashion_wbot/EXAMPLE
Правила: https://example.com/promo/promo_rules.pdf
E-mail поддержки: promo@example.com
";
	$buttons = [
    	[
        	[
            	'text' => 'Добавить покупку',
            	'callback_data' => '/order',
        	]
    	],
	];
	break;

При получении команды /start метод setBotData() бот очищает данные о текущем пользователе (по идентификатору чата), устанавливая пустой массив. Также состояние бота переводится в start при помощи метода setBotState(), что используется для управления логикой дальнейших взаимодействий.

Помимо этого, заполняется приветственное сообщение с ссылками на сайт и правила в переменную $textReturn, которые будут отправлены пользователю. После чего инициализируется массив $buttons, который содержит кнопку «Добавить покупку», позволяющую пользователю инициировать следующий шаг.

Обработка команды /order

case '/order':
case 'Добавить покупку':
	$telegram->setBotData($chatId, []);
	$telegram->setBotState($chatId, 'barcode');
	$textReturn = "Сейчас Вам необходимо будет ввести данные. Пожалуйста, следуйте инструкции. Введите штрихкод:";
	break;

Если пользователь отправляет команду /order или нажимает кнопку «Добавить покупку», то данные о пользователе очищаются повторно на случай если в них остались данные. 

Также устанавливается состояние бота в barcode, что указывает на то, что тот ожидает ввода штрихкода от пользователя. А в переменную $textReturn фиксируется инструкция для пользователя о вводе данных.

Обработка отмены добавления покупки

case 'У меня нет чека, не добавлять покупку':
case 'У меня нет штрихкода':
case '/no_photo':
	$telegram->setBotBarcode($chatId, []);
	$telegram->setBotData($chatId, []);
	$telegram->setBotState($chatId, 'start');
	$textReturn = "Вы отменили добавление покупки. Вы можете добавить новую.";
	$buttons = [
    	[
        	[
            	'text' => 'Добавить покупку',
            	'callback_data' => '/order',
        	]
    	],
	];
	break;

Если получены сообщения о том, что чек или штрихкод отсутствуют:

  • удаляются данные пользователя;

  • состояние бота переводится обратно в start

  • пользователю приходит сообщение, что добавление покупки отменено;

  • поступает предложение начать процесс заново.

Кроме того, создаются кнопки для повтора процесса добавления покупки.

Обработка команды /about

case '/about':
	$textReturn = "Добро пожаловать!
Ссылка на сайт: https://t.me/Fashion_wbot/EXAMPLE
Правила: https://example.com/promo/promo_rules.pdf
";
	break;

При получении команды /about выводится только информация о боте со ссылками на сайт акции и правила.

Обработка команды /help

case '/help':
	$textReturn = "Список команд:
/help - список команд
/about - о нас
/order - добавить покупку
";
	break;

При запросе команды /help в переменную $textReturn заносится список доступных команд, которые пользователь может использовать для взаимодействия с ботом.

Обработка данных, которые вводит клиент

Когда бот продолжает взаимодействие с пользователем, то в работу вступает данный блок. Он отрабатывает под командой default оператора switch и реализует логику обработки ввода данных.

Код также использует конструкцию switch, которая позволяет обрабатывать различные состояния бота, определяемые переменной $botStatus.

Ниже список вводимых данных в зависимости от состояния.

  1. Обработка ввода штрихкодов

case 'barcode':
	if (is_numeric($text)) {
    	if (
        	($telegram->checkBarcodeCsv($text) || $telegram->checkBarcodeSilverCsv($text)) &&
        	!$telegram->checkBarcodeBuyer($text) &&
        	!$telegram->checkBarcodeStopList($text)
    	) {
        	$textReturn = "Штрихкод {$text} прошел проверку и будет добавлен по завершении регистрации покупки.
Теперь введите, пожалуйста, Ваше ФИО";
        	$clientData[0] = $text;
        	$telegram->setBotState($chatId, 'name');
    	} else {
        	$textReturn = "Штрихкод {$text} не верифицирован. Ввести ещё штрихкод?";
    	}
	} else {
    	$textReturn = "Пожалуйста, введите корректный штрихкод";
    	$buttons = [
        	[
            	[
                	'text' => 'У меня нет штрихкода',
                	'callback_data' => '/no_photo',
            	]
        	],
    	];
	}
	break;

В этом блоке обрабатывается состояние barcode, когда бот ожидает ввод штрихкода от пользователя. На данном этапе проверяется, является ли введенный текст числом с помощью функции is_numeric().

  • Если это не так, то пользователю отправляется сообщение с просьбой ввести корректный штрихкод.

  • Если введенный текст является числом, выполняется проверка штрихкода с использованием методов checkBarcodeCsv(), checkBarcodeSilverCsv(), а также проверяется, нет ли штрихкода в списке покупателей и стоп-листе.

  • Если штрихкод проходит все проверки, пользователю отправляется сообщение о том, что он успешно прошел верификацию, и запрашивается ввод ФИО.

  • Введенный штрихкод сохраняется в массиве$clientData по индексу 0.

  • Если же штрихкод не прошел верификацию, пользователю предлагается ввести его повторно.

2. Обработка ввода ФИО

case 'name':
	$clientData[2] = $text;
	$telegram->setBotState($chatId, 'phone');
	$textReturn = "Теперь введите телефон";
	break;

Если бот находится в состоянии name, это означает, что пользователь должен ввести свои ФИО. Введенные данные сохраняются в массиве $clientData по индексу 2.

Также устанавливается новое состояние бота — phone, которое указывает на то, что бот ожидает ввод номера телефона, а пользователь получает сообщение с просьбой указать телефон.

3. Обработка ввода телефона

case 'phone':
	$clientData[3] = $text;
	$telegram->setBotState($chatId, 'photo');
	$textReturn = "Прикрепите фото чека";
	$buttons = [
    	[
        	[
            	'text' => 'У меня нет чека, не добавлять покупку',
            	'callback_data' => '/no_photo',
        	]
    	],
	];
	break;

В состоянии phone бот ожидает от пользователя ввода номера телефона. Номер сохраняется в массиве $clientData по индексу 3. 

Также устанавливается новое состояние бота photo, что указывает на ожидание от пользователя фотографии чека, а пользователь получает сообщение с просьбой прикрепить фото, также создаются кнопки для отмены добавления покупки.

4. Обработка отправленных фотографий

case 'photo':
	$telegram->setBotState($chatId, 'save');
	$textReturn = "Вы успешно добавили покупку! Теперь Вы можете добавить новую.";
	$buttons = [
    	[
        	[
            	'text' => 'Добавить покупку',
            	'callback_data' => '/order',
        	]
    	],
	];
	break;

Если бот находится в состоянии photo, это означает, что пользователь должен прикрепить фотографию чека. После прикрепления чека происходит проверка на загрузку фото.

if ($botStatus == 'photo' && ($image || $document)) {

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

После этого производится извлечение идентификатора файла. Сначала мы определяем, какой из типов изображений (приложенное фото или документ) используется у нас, и получаем параметр file_id.

$fileId = '';
if ($image) {
	$imageArray = end($image);
	$fileId = $imageArray['file_id'];
} elseif ($document) {
	$fileId = $document['file_id'];
}

Далее проверяется, был ли успешно получен file_id. Если он существует, вызывается метод getImage() для получения пути к изображению на сервере.

if ($fileId)
	$filePath = $telegram->getImage($fileId);

Если путь к файлу был успешно получен, он сохраняется в массиве $clientData по индексу 4. 

Также устанавливается новое состояние бота save, что указывает на завершение процесса добавления покупки. Пользователь получает сообщения «Покупка успешно добавлена» и «Вы можете добавить новую покупку».

Создаются кнопки для повтора процесса.

if ($filePath) {
	$clientData[4] = $filePath;
	$telegram->setBotState($chatId, 'save');
	$textReturn = "Вы успешно добавили покупку! Теперь Вы можете добавить новую.";
	$buttons = [
    	[
        	[
            	'text' => 'Добавить покупку',
            	'callback_data' => '/order',
        	]
    	],
	];
}

Если же путь к файлу не был получен, например, файл некорректен, то пользователь получает сообщение об этом и предложение попробовать снова. Также создаются кнопки для отмены добавления покупки.

else {
	$textReturn = "Чек некорректный. Попробуйте снова.";
	$buttons = [
    	[
        	[
            	'text' => 'У меня нет чека, не добавлять покупку',
            	'callback_data' => '/no_photo',
        	]
    	],
	];
}

5. Сохранение данных клиента

$telegram->setBotData($chatId, $clientData);

Данные клиента сохраняются в боте в конце каждого ввода.

Метод setBotData() обновляет информацию о клиенте по идентификатору чата с помощью массива $clientData, который содержит все введенные пользователем данные: штрихкод, ФИО, телефон.

Сохранение данных

Если текущее состояние бота — save, то происходит финальная проверка состояния бота и данные покупателя сохраняются.

if ($telegram->getBotState($chatId) == 'save') {
	$clientData[1] = $telegram->getIdBuyer();
	$telegram->saveDataBuyer($clientData);

	$telegram->setBotData($chatId, []);
	$telegram->setBotState($chatId, 'start');
}

В массив с данными клиента $clientData добавляется идентификатор покупателя, который получен с помощью метода getIdBuyer()

Затем вызывается метод saveDataBuyer(), который сохраняет данные о покупке в БД. После этого очищается массив данных клиента, и состояние бота сбрасывается на начальное — start

Это позволяет пользователю добавить новую покупку.

Доверяй и проверяй

После того как акция закончилась, появилась возможность оценить, как повлияло использование ботов. Мы специализируемся на e-commerce и на сайтах клиентов регулярно проводим онлайн-опросы, в том числе по удовлетворенности внедрением новых функций.

Первое, что сделали, — провели опрос среди участников акции с помощью того же бота. 

Задали вопросы:

  • «Было ли вам удобно пользоваться ботом?»

  • «Где вам удобнее регистрироваться: на сайте или в телеграме?»

Получили следующие ответы:

  • 73% высказались, что бот был им удобен.

  • 80% ответили, что предпочтут работу в ТГ-боте, вместо регистрации на сайте.

Также запросили данные по результатам у команды клиента. Коммерческие показатели нам недоступны, но есть такие:

  • Если раньше регистрация на сайте длилась до 30 дней — все время проведения акции, то ТГ-боты сократили время регистрации у 85% участников до 7 дней. То есть в основном люди регистрировали покупки сразу, не откладывая это в долгий ящик.

  • Провели опрос среди сотрудников 4 салонов ювелирной сети, в которых проходила акция. Подавляющее большинство указало, что их трудозатраты на обслуживание акции сократились на 67%. То есть ТГ-боты однозначно облегчили работу и снизили количество ошибок.

Еще один несомненный плюс — это сбор данных и статистика по покупателям. Это дало возможность персонализировать будущие предложения и точечно настраивать новые акции, чтобы и продавец получил выгоду, и клиенты были довольны.

Расскажите, использовали ли вы ботов на своих проектах? Поделитесь в комментариях своим опытом.

Теги:
Хабы:
+8
Комментарии1

Публикации

Информация

Сайт
o2k.ru
Дата регистрации
Дата основания
Численность
51–100 человек
Местоположение
Россия
Представитель
Максим Жуков