Как настроить интеграцию 1С с Telegram и правильно передавать данные?

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

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

Основы взаимодействия: Отправка сообщений из 1С в Telegram

Для начала рассмотрим классический пример отправки текстового сообщения из 1С в чат Telegram. Взаимодействие строится на отправке HTTP-запросов к серверу Telegram API. Чтобы отправить сообщение, нам понадобятся две вещи: токен бота (выдается при создании бота у отца всех ботов — @BotFather) и идентификатор чата (chat_id) получателя.

Проанализируем практический пример реализации такой отправки на встроенном языке 1С. Допустим, нам необходимо информировать руководство или ответственного менеджера о пробитии чека ККМ в конфигурации «1С:Розница». Для этого мы перехватим событие проведения документа и выполним отправку сообщения.


&НаСервере
Процедура ПриПроведенииЧекаОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт
    
    Если Источник.СтатусЧекаККМ = Перечисления.СтатусыЧековККМ.Пробитый Тогда
            
        // Формируем текст сообщения        
        ТекстЧек = Строка(Источник) + " (статус: " + Строка(Источник.СтатусЧекаККМ) + ")";
        
        Товары = "Товары: " + Символы.ПС;
        Для Каждого Строка Из Источник.Товары Цикл
            Товары = Товары + Строка.Номенклатура.Наименование + ": " + 
            Строка(Строка.Количество) + " " + 
            Строка(Строка.Номенклатура.ЕдиницаИзмерения.Наименование) + 
            " по " + Строка(Строка.Цена) + " = " + Строка(Строка.Сумма) + 
            ?(Строка.ПроцентАвтоматическойСкидки <> 0, " (Автоскидка = " + Строка(Строка.ПроцентАвтоматическойСкидки) + "%; Сумма автоскидки = " + Строка(Строка.СуммаАвтоматическойСкидки), "")  +
            ?(Строка.ПроцентРучнойСкидки <> 0, " (Ручнаяскидка = " + Строка(Строка.ПроцентРучнойСкидки) + "%; Сумма ручной скидки = " + Строка(Строка.СуммаРучнойСкидки), "")  +
             ";" + Символы.ПС;
        КонецЦикла;
        
        ТекстСумма = "Сумма чека: " + Строка(Источник.СуммаДокумента);
        
        ТекстОплаты = "Оплата: ";
        Для Каждого Строка Из Источник.Оплата Цикл
            ТекстОплаты = ТекстОплаты + Строка(Строка.ВидОплаты.Наименование) + ": " + Строка(Строка.Сумма);
        КонецЦикла;
        
        ТекстСкидки = "Скидки: ";
        Для Каждого Строка Из Источник.СкидкиНаценки Цикл
            ТекстСкидки = ТекстСкидки + Строка(Строка.СкидкаНаценка) + ": " + Строка(Строка.Сумма) + Символы.ПС;
        КонецЦикла;
        
        ТекстСообщения = ТекстЧек + "; " + Символы.ПС + Товары + "; " + Символы.ПС + ТекстСумма + Символы.ПС + ТекстОплаты + Символы.ПС + ТекстСкидки;
        
        // Параметры подключения к Telegram API
        Сервер = "api.telegram.org";
        Токен = "Укажите_Здесь_Ваш_Токен";
        ID = "Укажите_Здесь_Ваш_Chat_ID";
        
        // ВНИМАНИЕ: Данный способ формирования ресурса содержит уязвимость для спецсимволов!
        Ресурс = "bot" + Токен + "/SendMessage?chat_id=" + ID + "&text=" + ТекстСообщения;
        
        Соединение = Новый HTTPСоединение(Сервер, 443, , , , 5, Новый ЗащищенноеСоединениеOpenSSL());
        Запрос = Новый HTTPЗапрос(Ресурс);
        Ответ = Соединение.Получить(Запрос);
            
    КонецЕсли;
        
КонецПроцедуры

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

Решение проблемы с кодированием спецсимволов и переносом строк (URLEncode)

Если в переменной ТекстСообщения присутствует хотя бы один символ перевода строки (Символы.ПС), пробел или кириллический символ, платформа 1С вернет ошибку выполнения HTTP-запроса: "Ошибка работы с Интернет: URL using bad/illegal format or missing URL".

Выясним причину этой ошибки. При передаче параметров методом GET все специальные символы, кириллица, пробелы и управляющие символы (такие как перевод строки) должны быть преобразованы в специальный формат, пригодный для URL-адресов. Этот процесс называется URL Encoding (процентное кодирование).

Если вы используете GET-запросы, вам потребуется функция преобразования строки в URL-совместимый формат. Рассмотрим, как реализовать такую функцию на встроенном языке 1С без использования внешних компонент:


Функция КодСимволаASCII(Символ) 
   КодUNICODE = КодСимвола(Символ); 
   Если ((КодUNICODE > 1039) И (КодUNICODE < 1104)) Тогда 
       Возврат (КодUNICODE - 848); 
   ИначеЕсли КодUNICODE = 8470 Тогда 
       Возврат 185; 
   ИначеЕсли КодUNICODE = 1105 Тогда 
       Возврат 184; 
   ИначеЕсли КодUNICODE = 1025 Тогда 
       Возврат 168; 
   Иначе 
       Возврат КодUNICODE; 
   КонецЕсли; 
КонецФункции

Функция URLEncode(Знач Значение) Экспорт
    ТаблицаПерекодировки = "%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14" +
            "%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28" +
            "%29%2A%2B%2C%2D%2E%2F%30%31%32%33%34%35%36%37%38%39%3A%3B%3C" +
            "%3D%3E%3F%40%41%42%43%44%45%46%47%48%49%4A%4B%4C%4D%4E%4F%50" +
            "%51%52%53%54%55%56%57%58%59%5A%5B%5C%5D%5E%5F%60%61%62%63%64" +
            "%65%66%67%68%69%6A%6B%6C%6D%6E%6F%70%71%72%73%74%75%76%77%78" +
            "%79%7A%7B%7C%7D%7E%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C" +
            "%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0" +
            "%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4" +
            "%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8" +
            "%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC" +
            "%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0" +
            "%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF";
    
    Результат = "";        
    ДлинаСтроки = СтрДлина(Значение);        
    
    Для Шаг = 1 По ДлинаСтроки Цикл        
        ТекущийСимвол = Сред(Значение, Шаг, 1);        
        КодСимволаASCII = КодСимволаASCII(ТекущийСимвол);
        Результат = Результат + Сред(ТаблицаПерекодировки, КодСимволаASCII * 3 + 1, 3);        
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

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


ЗакодированныйТекст = URLEncode(ТекстСообщения);
Ресурс = "bot" + Токен + "/SendMessage?chat_id=" + ID + "&text=" + ЗакодированныйТекст;

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

Современная альтернатива: Переход на POST-запросы и JSON

Несмотря на работоспособность метода GET с кодированием URL, этот подход считается устаревшим и имеет серьезные ограничения по объему передаваемых данных (максимальная длина URL-строки ограничена). Более надежным и профессиональным стандартом является использование метода POST с телом запроса в формате JSON.

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


&НаСервере
Процедура ОтправитьСообщениеПост(Токен, ChatID, ТекстСообщения)
    
    Сервер = "api.telegram.org";
    Ресурс = "bot" + Токен + "/sendMessage";
    
    // Формируем структуру данных для отправки
    ПараметрыЗапроса = Новый Структура;
    ПараметрыЗапроса.Вставить("chat_id", ChatID);
    ПараметрыЗапроса.Вставить("text", ТекстСообщения);
    ПараметрыЗапроса.Вставить("parse_mode", "Markdown"); // Поддержка форматирования
    
    // Сериализуем структуру в JSON
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
    СтрокаJSON = ЗаписьJSON.Закрыть();
    
    // Настраиваем HTTP-запрос
    Запрос = Новый HTTPЗапрос(Ресурс);
    Запрос.Заголовки.Вставить("Content-Type", "application/json");
    Запрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
    
    // Выполняем отправку
    Соединение = Новый HTTPСоединение(Сервер, 443, , , , 5, Новый ЗащищенноеСоединениеOpenSSL());
    Попытка
        Ответ = Соединение.ОтправитьДляОбработки(Запрос);
        Если Ответ.КодСостояния <> 200 Тогда
            ЗаписьЖурналаРегистрации("Telegram_Интеграция", УровеньЖурналаРегистрации.Предупреждение, , , Ответ.ПолучитьТелоКакСтроку());
        КонецЕсли;
    Исключение
        ЗаписьЖурналаРегистрации("Telegram_Интеграция", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
    КонецПопытки;

КонецПроцедуры

Данный вариант архитектуры исключает любые проблемы со спецсимволами, поддерживает разметку Markdown (выделение жирным шрифтом, курсивом) и готов к передаче больших объемов текста.

Интерактивные кнопки и обработка ответов пользователя (Callback Queries)

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

Для создания кнопок непосредственно под сообщением используется Inline Keyboard (инлайн-клавиатура). Каждой кнопке сопоставляется скрытый параметр — callback_data, который вернется в 1С при нажатии.

Рассмотрим пример формирования сообщения с кнопками на встроенном языке:


&НаСервере
Процедура ОтправитьКнопкиОтчетов(Токен, ChatID)
    
    Сервер = "api.telegram.org";
    Ресурс = "bot" + Токен + "/sendMessage";
    
    // Описываем инлайн-кнопки
    МассивКнопок = Новый Массив;
    
    Кнопка1 = Новый Структура("text, callback_data", "Продажи за день", "report_sales_day");
    Кнопка2 = Новый Структура("text, callback_data", "Остатки товаров", "report_stock");
    
    СтрокаКнопок = Новый Массив;
    СтрокаКнопок.Добавить(Кнопка1);
    СтрокаКнопок.Добавить(Кнопка2);
    
    МассивКнопок.Добавить(СтрокаКнопок);
    
    Клавиатура = Новый Структура("inline_keyboard", МассивКнопок);
    
    // Собираем тело запроса
    ПараметрыЗапроса = Новый Структура;
    ПараметрыЗапроса.Вставить("chat_id", ChatID);
    ПараметрыЗапроса.Вставить("text", "Выберите интересующий вас отчет:");
    ПараметрыЗапроса.Вставить("reply_markup", Клавиатура);
    
    ЗаписьJSON = Новый RecordJSON; // Инициализируем запись JSON
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
    СтрокаJSON = ЗаписьJSON.Закрыть();
    
    Запрос = Новый HTTPЗапрос(Ресурс);
    Запрос.Заголовки.Вставить("Content-Type", "application/json");
    Запрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
    
    Соединение = Новый HTTPСоединение(Сервер, 443, , , , 5, Новый ЗащищенноеСоединениеOpenSSL());
    Соединение.ОтправитьДляОбработки(Запрос);

КонецПроцедуры

Как только пользователь нажмет кнопку, Telegram отправит событие. Существует два способа его перехвата и обработки в 1С:

  1. Long Polling (Метод getUpdates): Регламентное задание в 1С с интервалом в несколько секунд обращается к адресу https://api.telegram.org/bot<Токен>/getUpdates, считывает массив новых событий, обрабатывает их и сохраняет идентификатор последнего обработанного события (offset). Этот метод прост, так как не требует публикации базы наружу, но создает задержки и нагружает сервер частыми холостыми запросами.
  2. Webhooks (Вебхуки): База 1С публикуется на веб-сервере (IIS или Apache) с поддержкой протокола HTTPS. В конфигурации создается собственный HTTP-сервис, адрес которого регистрируется на сервере Telegram через вызов метода setWebhook. Теперь при любом действии пользователя Telegram мгновенно присылает POST-запрос на ваш HTTP-сервис. Это идеальное решение с мгновенной реакцией бота.

При обработке входящего запроса от инлайн-кнопок вам придет структура JSON, содержащая объект callback_query. Ваша логика должна проанализировать поле data (там будет содержаться строка, например, "report_sales_day"), сгенерировать требуемый файл и отправить его обратно.

Важная рекомендация: После обработки нажатия инлайн-кнопки обязательно отправляйте ответный запрос методом answerCallbackQuery. Иначе пользователь будет наблюдать бесконечную анимацию загрузки на кнопке.

Формирование и отправка файлов из 1С в Telegram

Для отправки сформированных отчетов в форматах PDF или XLS используется метод Telegram API sendDocument. В отличие от текста, передача файлов требует использования формата тела запроса multipart/form-data.

Проанализируем пример кода для программного формирования печатной формы отчета в PDF и отправки полученного файла пользователю:


&НаСервере
Процедура СформироватьИОтправитьОтчет(Токен, ChatID, ИмяФайлаОтчета)
    
    // Шаг 1. Формируем печатную форму отчета в 1С
    // Допустим, у нас есть табличный документ ТабДок
    ТабДок = Новый ТабличныйДокумент;
    // ... здесь логика заполнения табличного документа ...
    
    ПутьКФайлу = ПолучитьИмяВременногоФайла("pdf");
    ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);
    
    // Шаг 2. Подготовка и отправка файла через HTTP-запрос (multipart/form-data)
    Сервер = "api.telegram.org";
    Ресурс = "bot" + Токен + "/sendDocument";
    
    Разделитель = "----" + Строка(Новый УникальныйИдентификатор);
    
    // Формируем тело запроса
    ТелоЗапроса = Новый ПотокВПамяти;
    ЗаписьТекста = Новый ЗаписьТекста(ТелоЗапроса, КодировкаТекста.UTF8);
    
    // Текстовый параметр chat_id
    ЗаписьТекста.ЗаписатьСтроку("--" + Разделитель);
    ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""chat_id""");
    ЗаписьТекста.ЗаписатьСтроку("");
    ЗаписьТекста.ЗаписатьСтроку(ChatID);
    
    // Параметр документа
    ЗаписьТекста.ЗаписатьСтроку("--" + Разделитель);
    ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""document""; filename=""" + ИмяФайлаОтчета + ".pdf""");
    ЗаписьТекста.ЗаписатьСтроку("Content-Type: application/pdf");
    ЗаписьТекста.ЗаписатьСтроку("");
    ЗаписьТекста.СовместитьСПотоком();
    
    // Записываем бинарные данные файла
    ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
    ДвоичныеДанныеФайла.Записать(ТелоЗапроса);
    
    // Закрываем границу запроса
    ЗаписьТекста.ЗаписатьСтроку("");
    ЗаписьТекста.ЗаписатьСтроку("--" + Разделитель + "--");
    ЗаписьТекста.СовместитьСПотоком();
    
    // Возвращаем указатель потока в начало
    ТелоЗапроса.Перейти(0, ПозицияВПотоке.Начало);
    
    // Отправляем запрос
    Запрос = Новый HTTPЗапрос(Ресурс);
    Запрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Разделитель);
    Запрос.УстановитьТелоИзПотока(ТелоЗапроса);
    
    Соединение = Новый HTTPСоединение(Сервер, 443, , , , 10, Новый ЗащищенноеСоединениеOpenSSL());
    Попытка
        Соединение.ОтправитьДляОбработки(Запрос);
    Исключение
        ЗаписьЖурналаРегистрации("Telegram_Файлы", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
    КонецПопытки;
    
    // Удаляем временный файл с диска
    УдалитьФайлы(ПутьКФайлу);
    
КонецПроцедуры

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

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

← На главную