Как получить и сохранить фото из Telegram в 1С?

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

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

Общая архитектура и принцип работы Telegram Bot API

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

Проанализируем полную цепочку взаимодействия между Telegram и 1С:

  1. Получение входящего события (Update): пользователь отправляет фото боту, и Telegram передает JSON-объект в 1С (через механизм Webhook или getUpdates).
  2. Извлечение идентификатора файла: парсим входящий JSON, находим массив photo или объект document и забираем file_id.
  3. Запрос информации о пути к файлу: отправляем GET-запрос к методу getFile Telegram Bot API, передавая полученный file_id. В ответ Telegram возвращает путь к файлу на своем сервере — file_path.
  4. Скачивание файла: выполняем прямой GET-запрос по пути /file/bot<Токен>/<file_path> и получаем двоичные данные изображения.
  5. Сохранение в 1С: записываем полученные данные в базу (в реквизит типа ХранилищеЗначения, справочник присоединенных файлов или на диск).

Шаг 1. Получение входящего сообщения в 1С через HTTP-сервис

Рассмотрим настройку приема сообщений через Webhook. Для этого в конфигураторе 1С создадим собственный HTTP-сервис с корневым шаблоном (например, /webhook) и методом POST.

Посмотрим на пример обработки входящего HTTP-запроса от Telegram:


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

КонецФункции

Шаг 2. Разбор структуры JSON и получение file_id

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

  1. Со сжатием (как фото): данные находятся в ветке message.photo. Это массив объектов с одним и тем же изображением в разных разрешениях. Последний элемент массива содержит максимальный размер и наилучшее качество.
  2. Без сжатия (как файл/документ): данные находятся в ветке 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;
        КонецЕсли;
    КонецЕсли;
    
    Если Не ПустаяСтрока(ИдентификаторФайла) Тогда
        ТокенБота = "ВАШ_ТОКЕН_БОТА";
        ДвоичныеДанныеФото = ПолучитьФайлИзТелеграм(ТокенБота, ИдентификаторФайла);
        
        Если ДвоичныеДанныеФото <> Неопределено Тогда
            СохранитьФотоВБазе(ДвоичныеДанныеФото, Сообщение);
        КонецЕсли;
    КонецЕсли;

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

Шаг 3. Получение пути к файлу и скачивание бинарных данных

Рассмотрим подробнее реализацию функции ПолучитьФайлИзТелеграм. Для взаимодействия с сервером 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ОтветФайла.КодСостояния);
        Возврат Неопределено;
    КонецЕсли;

КонецФункции

Шаг 4. Сохранение полученного изображения в 1С

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

  1. В реквизит справочника или документа: помещаем двоичные данные в реквизит с типом ХранилищеЗначения.
  2. В подсистему «Присоединенные файлы» (БСП): создаем элемент справочника присоединенных файлов через механизмы Библиотеки Стандартных Подсистем.
  3. На диск сервера: сохраняем файл в файловую систему с помощью метода Записать() объекта ДвоичныеДанные.

Посмотрим на пример сохранения в реквизит объекта информационной базы:


Процедура СохранитьФотоВБазе(ДвоичныеДанныеФото, Сообщение)
    
    // Пример: запись фото в справочник или регистр
    НоваяЗапись = РегистрыСведений.ВходящиеФотоТелеграм.СоздатьМенеджерЗаписи();
    НоваяЗапись.Период = ТекущаяДатаСессии();
    НоваяЗапись.IDСообщения = Сообщение.message_id;
    НоваяЗапись.IDПользователя = Сообщение.from.id;
    НоваяЗапись.ИмяПользователя = ?(Сообщение.from.Свойство("username"), Сообщение.from.username, "");
    
    // Упаковываем двоичные данные в ХранилищеЗначения
    НоваяЗапись.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанныеФото, Новый СжатиеДанных(9));
    НоваяЗапись.Записать();
    
КонецПроцедуры

Важные ограничения и рекомендации

← На главную