При интеграции 1С с Telegram часто возникает задача не только отправлять уведомления и печатные формы пользователям, но и принимать входящие файлы: фотографии чеков, накладных, сканы документов или фотоотчеты торговых представителей. В отличие от отправки данных, где достаточно вызвать метод sendPhoto, процесс получения и обработки входящих файлов в 1С требует понимания архитектуры Telegram Bot API. Разберем по шагам, как устроен этот механизм и как правильно реализовать прием изображений в 1С.
Telegram не присылает само бинарное тело изображения напрямую во входящем вебхуке или при опросе. Вместо этого сервер передает служебный объект с метаданными и уникальным идентификатором файла — file_id.
Проанализируем полную цепочку взаимодействия между Telegram и 1С:
Webhook или getUpdates).photo или объект document и забираем file_id.getFile Telegram Bot API, передавая полученный file_id. В ответ Telegram возвращает путь к файлу на своем сервере — file_path./file/bot<Токен>/<file_path> и получаем двоичные данные изображения.ХранилищеЗначения, справочник присоединенных файлов или на диск).Рассмотрим настройку приема сообщений через Webhook. Для этого в конфигураторе 1С создадим собственный HTTP-сервис с корневым шаблоном (например, /webhook) и методом POST.
Посмотрим на пример обработки входящего HTTP-запроса от Telegram:
Функция webhookОбработкаPOST(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
// Получаем тело запроса в виде строки
СтрокаJSON = Запрос.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
Если ПустаяСтрока(СтрокаJSON) Тогда
Возврат Ответ;
КонецЕсли;
// Читаем входящий JSON
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
ДанныеОбновления = ПрочитатьJSON(ЧтениеJSON, Ложь);
ЧтениеJSON.Закрыть();
// Передаем данные на обработку
ОбработатьВходящееСообщение(ДанныеОбновления);
Возврат Ответ;
КонецФункции
Выясним, как устроена структура входящего объекта при отправке изображения. Пользователь может отправить фото двумя способами:
message.photo. Это массив объектов с одним и тем же изображением в разных разрешениях. Последний элемент массива содержит максимальный размер и наилучшее качество.message.document, где указан file_id и mime_type.Разберем функцию извлечения file_id из структуры:
Процедура ОбработатьВходящееСообщение(ДанныеОбновления)
Если Не ДанныеОбновления.Свойство("message") Тогда
Возврат;
КонецЕсли;
Сообщение = ДанныеОбновления.message;
ИдентификаторФайла = "";
// Вариант 1: Отправлено фото со сжатием
Если Сообщение.Свойство("photo") И ТипЗнч(Сообщение.photo) = Тип("Массив") Тогда
КоличествоФото = Сообщение.photo.Количество();
Если КоличествоФото > 0 Тогда
// Берем последний элемент с наилучшим качеством
ФотоМаксКачества = Сообщение.photo[КоличествоФото - 1];
ИдентификаторФайла = ФотоМаксКачества.file_id;
КонецЕсли;
// Вариант 2: Отправлено фото как документ (без сжатия)
ИначеЕсли Сообщение.Свойство("document") Тогда
Документ = Сообщение.document;
Если Документ.Свойство("mime_type") И СтрНачинаетсяС(Документ.mime_type, "image/") Тогда
ИдентификаторФайла = Документ.file_id;
КонецЕсли;
КонецЕсли;
Если Не ПустаяСтрока(ИдентификаторФайла) Тогда
ТокенБота = "ВАШ_ТОКЕН_БОТА";
ДвоичныеДанныеФото = ПолучитьФайлИзТелеграм(ТокенБота, ИдентификаторФайла);
Если ДвоичныеДанныеФото <> Неопределено Тогда
СохранитьФотоВБазе(ДвоичныеДанныеФото, Сообщение);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Рассмотрим подробнее реализацию функции ПолучитьФайлИзТелеграм. Для взаимодействия с сервером api.telegram.org обязательно используем защищенное соединение Новый ЗащищенноеСоединениеOpenSSL() и порт 443.
Посмотрим на пример кода получения файла:
Функция ПолучитьФайлИзТелеграм(ТокенБота, FileID)
СерверTelegram = "api.telegram.org";
Защита = Новый ЗащищенноеСоединениеOpenSSL();
// 1. Запрашиваем путь к файлу через метод getFile
СоединениеAPI = Новый HTTPСоединение(СерверTelegram, 443, , , , 30, Защита);
АдресЗапроса = "/bot" + ТокенБота + "/getFile?file_id=" + FileID;
HTTPЗапрос = Новый HTTPЗапрос(АдресЗапроса);
HTTPОтвет = СоединениеAPI.Получить(HTTPЗапрос);
Если HTTPОтвет.КодСостояния <> 200 Тогда
ЗаписьЖурналаРегистрации("TelegramBot", УровеньЖурналаРегистрации.Ошибка, , , "Ошибка getFile: " + HTTPОтвет.ПолучитьТелоКакСтроку());
Возврат Неопределено;
КонецЕсли;
// Разбираем ответ JSON
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(HTTPОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
ОтветAPI = ПрочитатьJSON(ЧтениеJSON, Ложь);
ЧтениеJSON.Закрыть();
Если Не (ОтветAPI.Свойство("ok") И ОтветAPI.ok И ОтветAPI.Свойство("result")) Тогда
Возврат Неопределено;
КонецЕсли;
ПутьКФайлу = ОтветAPI.result.file_path; // Например, "photos/file_0.jpg"
// 2. Скачиваем сам файл по полученному пути
АдресСкачивания = "/file/bot" + ТокенБота + "/" + ПутьКФайлу;
HTTPЗапросФайла = Новый HTTPЗапрос(АдресСкачивания);
HTTPОтветФайла = СоединениеAPI.Получить(HTTPЗапросФайла);
Если HTTPОтветФайла.КодСостояния = 200 Тогда
Возврат HTTPОтветФайла.ПолучитьТелоКакДвоичныеДанные();
Иначе
ЗаписьЖурналаРегистрации("TelegramBot", УровеньЖурналаРегистрации.Ошибка, , , "Ошибка скачивания файла: " + HTTPОтветФайла.КодСостояния);
Возврат Неопределено;
КонецЕсли;
КонецФункции
После того как двоичные данные успешно получены, мы можем сохранить их в информационной базе 1С. Рассмотрим несколько типовых способов сохранения:
ХранилищеЗначения.Записать() объекта ДвоичныеДанные.Посмотрим на пример сохранения в реквизит объекта информационной базы:
Процедура СохранитьФотоВБазе(ДвоичныеДанныеФото, Сообщение)
// Пример: запись фото в справочник или регистр
НоваяЗапись = РегистрыСведений.ВходящиеФотоТелеграм.СоздатьМенеджерЗаписи();
НоваяЗапись.Период = ТекущаяДатаСессии();
НоваяЗапись.IDСообщения = Сообщение.message_id;
НоваяЗапись.IDПользователя = Сообщение.from.id;
НоваяЗапись.ИмяПользователя = ?(Сообщение.from.Свойство("username"), Сообщение.from.username, "");
// Упаковываем двоичные данные в ХранилищеЗначения
НоваяЗапись.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанныеФото, Новый СжатиеДанных(9));
НоваяЗапись.Записать();
КонецПроцедуры
file_path является временным и обычно действителен в течение одного часа, поэтому скачивание файла необходимо производить сразу после получения события.