Как обработать нажатие кнопок и ответы пользователя в Telegram-боте на 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разработка Telegram-ботов на платформе 1С становится всё более востребованной задачей для автоматизации бизнес-процессов: от подтверждения заявок до уведомления о критических событиях. В этой статье мы подробно разберем, как не только отправить пользователю сообщение с вариантами выбора, но и правильно обработать его ответ, особенно если речь идет об интерактивных кнопках.

Создание и отправка сообщения с Inline-кнопками

Для начала рассмотрим ситуацию, когда нам необходимо отправить пользователю сообщение с кнопками "Разблокировать" и "Не разблокировать". В Telegram существует два основных типа клавиатур: ReplyKeyboardMarkup (обычные кнопки вместо текстовой клавиатуры) и InlineKeyboardMarkup (кнопки, привязанные непосредственно к сообщению). Для обработки конкретных действий программисты чаще всего выбирают именно Inline-кнопки.

Проанализируем пример кода на стороне 1С для формирования такой клавиатуры:


&НаСервере
Процедура ОтправитьСообщениеНаСервере()
    
    мСтрок = Новый Массив;
    мКнопок = Новый Массив;
    
    // Формируем кнопки. В callback_data передаем идентификатор действия
    мКнопок.Добавить(Новый Структура("text, callback_data", "Разблокировать", "1"));
    мКнопок.Добавить(Новый Структура("text, callback_data", "Не разблокировать", "2"));
    
    мСтрок.Добавить(мКнопок);
    
    СтруктураОтвета = Новый Структура;
    СтруктураОтвета.Вставить("inline_keyboard", мСтрок);
    
    // Сериализуем структуру в JSON для передачи через API
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет,,,ЭкранированиеСимволовJSON.СимволыВнеASCII));
    ЗаписатьJSON(ЗаписьJSON, СтруктураОтвета);
    Клавиатура = ЗаписьJSON.Закрыть();
    
    // Формируем ресурс и отправляем запрос
    Ресурс = "bot" + Объект.ТокенБота + "/sendMessage?chat_id=" + Формат(ChatID, "ЧГ=0") + "&text=" + ТекстСообщения 
            + "&reply_markup=" + Клавиатура;
            
    Соединение = Новый HTTPСоединение("api.telegram.org", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
    Запрос = Новый HTTPЗапрос(Ресурс);
    Ответ = Соединение.Получить(Запрос);
    
КонецПроцедуры

В данном примере крайне важно поле callback_data. Именно это значение (в нашем случае "1" или "2") вернется в 1С, когда пользователь нажмет на кнопку. Текст кнопки при этом в обработку не попадает, что удобно для локализации или изменения визуальной части без правки логики.

Почему при нажатии на кнопку не приходит текст сообщения?

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

Telegram разделяет типы входящих данных:

  1. Если пользователь просто пишет текст — данные приходят в объекте message.
  2. Если пользователь нажимает на Inline-кнопку — данные приходят в объекте callback_query.

Посмотрим на структуру входящего JSON при нажатии на кнопку:


{
 "update_id": 123456789,
 "callback_query": {
  "id": "12345",
  "from": { "id": 987654321, "first_name": "Иван" },
  "message": { "message_id": 456, "text": "Вариант ответа?" },
  "data": "1"
 }
}

Как мы видим, текст нажатой кнопки или ответ пользователя нужно искать в callback_query.data. Если вы анализируете только message, то нажатие на кнопку будет проигнорировано.

Способ 1: Использование метода getUpdates (Long Polling)

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

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


Процедура ОбработатьОбновления()
    // Последний обработанный UpdateID храним в константе или параметрах
    ПоследнийID = Константы.ПоследнийUpdateID.Получить();
    
    Ресурс = "bot" + Токен + "/getUpdates?offset=" + Формат(ПоследнийID + 1, "ЧГ=0");
    // Отправляем запрос...
    
    // После получения JSON, разбираем его:
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(СтрокаОтветаJSON);
    Данные = ПрочитатьJSON(Чтение);
    
    Для Каждого Обновление Из Данные.result Цикл
        Если Обновление.Свойство("callback_query") Тогда
            // Обрабатываем нажатие кнопки
            КодДействия = Обновление.callback_query.data;
            Если КодДействия = "1" Тогда
                // Логика разблокировки
            КонецЕсли;
            
            // ОБЯЗАТЕЛЬНО: подтверждаем получение callback_query
            ОтправитьПодтверждениеCallback(Обновление.callback_query.id);
        ИначеЕсли Обновление.Свойство("message") Тогда
            // Обрабатываем обычный текст
            ТекстОтвета = Обновление.message.text;
        КонецЕсли;
        
        ПоследнийID = Обновление.update_id;
    КонецЦикла;
    
    Константы.ПоследнийUpdateID.Установить(ПоследнийID);
КонецПроцедуры

Важный нюанс: Метод answerCallbackQuery. Если не отправить этот запрос после обработки callback_query, у пользователя на кнопке будет продолжать крутиться индикатор ожидания (часики). Рассмотрим, как его вызвать:


Процедура ОтправитьПодтверждениеCallback(IDЗапроса)
    Ресурс = "bot" + Токен + "/answerCallbackQuery?callback_query_id=" + IDЗапроса;
    // Можно также добавить параметр text, чтобы показать всплывающее уведомление
    Запрос = Новый HTTPЗапрос(Ресурс);
    Соединение.Получить(Запрос);
КонецПроцедуры

Способ 2: Настройка Webhook и HTTP-сервиса в 1С

Для более высоконагруженных или оперативных систем рекомендуется использовать Webhook. В этом случае Telegram сам будет присылать данные в вашу 1С в момент совершения действия пользователем. Разберем по шагам, как это реализовать.

1. Создание HTTP-сервиса в конфигурации:

Создадим новый объект HTTP-сервис (например, с именем TelegramWebhook). В нем определим шаблон URL и метод POST. В обработчике метода мы будем считывать тело запроса:


Функция ОбработатьВходящийЗапрос(Запрос)
    
    ТелоJSON = Запрос.ПолучитьТелоКакСтроку();
    // Далее логика разбора JSON, аналогичная getUpdates
    // ...
    
    Ответ = Новый HTTPСервисОтвет(200); // Обязательно возвращаем 200 OK
    Возврат Ответ;
    
КонецФункции

2. Регистрация Webhook:

Чтобы Telegram узнал, куда слать данные, нужно один раз вызвать метод setWebhook. Проанализируем требования:


// Пример регистрации
Ресурс = "bot" + Токен + "/setWebhook?url=https://myserver.com/base/hs/TelegramWebhook/v1";
Запрос = Новый HTTPЗапрос(Ресурс);
Ответ = Соединение.Получить(Запрос);

3. Обеспечение безопасности:

Поскольку ваш HTTP-сервис теперь доступен из интернета, выясним, как защитить его от поддельных запросов. Рекомендуется включить в URL секретный токен, известный только вам и Telegram:

https://myserver.com/base/hs/Telegram/SECRET_GUID_HERE

В коде 1С проверяйте этот GUID в начале обработки запроса.

Сравнение подходов

Проанализируем ситуацию: какой метод выбрать? getUpdates идеально подходит для внутренних нужд предприятия, когда 1С находится за NAT, и вы не хотите возиться с пробросом портов и SSL-сертификатами. Однако он создает лишнюю нагрузку на сервер из-за постоянных опросов.

Webhook работает быстрее, экономит ресурсы сервера и считается более профессиональным подходом, но требует публикации базы и настройки веб-сервера (Apache или IIS) с поддержкой защищенного соединения.

Независимо от выбранного способа, помните, что работа с Telegram — это всегда работа с объектами 1С ЧтениеJSON и ЗаписьJSON. Правильное обращение к свойствам структуры (Обновление.callback_query.data вместо Обновление.message.text) — ключ к успешной обработке действий пользователя.

← На главную