Как получить табличный документ (печатную форму) через COM-соединение в 1С?

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

В практике интеграции систем на платформе 1С:Предприятие часто возникает задача: сформировать печатную форму в одной информационной базе (например, в старой и нетиповой или, наоборот, в закрытой типовой конфигурации) и отобразить её в другой, современной базе на управляемых формах. При этом напрямую передать объект типа ТабличныйДокумент через COM-соединение невозможно, так как вызывающий процесс получит лишь COM-объект, с которым нельзя полноценно работать на клиенте базы-приемника.

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

Почему нельзя передать табличный документ напрямую?

COM-соединение (с использованием объекта V83.COMConnector) накладывает жесткие ограничения на типы передаваемых данных. Напрямую между базами можно передавать только примитивные типы (числа, строки, даты, булево). Любые сложные объекты 1С (документы, справочники, табличные документы) передаются как ссылки на COM-объекты. Попытка вывести такой "чужой" табличный документ на форму в вашей базе приведет к ошибке отображения или полному отсутствию интерактивности.

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


Способ 1. Сериализация через ЗначениеВСтрокуВнутр (Быстрый способ)

Этот способ основан на преобразовании табличного документа в системную строку внутреннего формата 1С на стороне COM-сервера и последующем его восстановлении на стороне клиента.

Рассмотрим по шагам, как выглядит данный процесс в коде:


// Код на стороне базы-приемника (Управляемые формы)
&НаСервере
Функция ПолучитьТабличныйДокументЧерезCOMСериализацию(ПараметрыПодключения, ИдентификаторДокумента)
    
    // 1. Устанавливаем COM-соединение с базой-источником
    COMСоединение = Новый COMОбъект("V83.COMConnector");
    Попытка
        БазаИсточник = COMСоединение.Connect(ПараметрыПодключения);
    Исключение
        ВызватьИсключение "Не удалось подключиться к базе-источнику: " + ОписаниеОшибки();
    КонецПопытки;
    
    // 2. Находим нужный документ в базе-источнике (например, Реализацию товаров и услуг)
    ДокументСсылкаCOM = БазаИсточник.Документы.РеализацияТоваровУслуг.НайтиПоРеквизиту("Номер", ИдентификаторДокумента);
    Если ДокументСсылкаCOM.Пустая() Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    // 3. Формируем табличный документ на стороне источника и сериализуем его в строку.
    // Используем системную функцию базы-источника через COM-объект.
    СтрокаТабличногоДокумента = БазаИсточник.ЗначениеВСтрокуВнутр(
        БазаИсточник.УчетНДС.ПечатьУниверсальногоПередаточногоДокумента(ДокументСсылкаCOM, Ложь)
    );
    
    // 4. Восстанавливаем табличный документ в локальной базе из полученной строки
    ЛокальныйТабДок = ЗначениеИзСтрокиВнутр(СтрокаТабличногоДокумента);
    
    Возврат ЛокальныйТабДок;
    
КонецФункции

Ограничения и недостатки сериализации:

  1. Потеря расшифровки (мутабельные значения): Если в ячейках оригинального табличного документа были настроены расшифровки (например, ссылки на договоры, контрагентов или первичные документы), при десериализации в целевой базе они превратятся в недействительные ссылки или вызовут ошибку, так как GUID-ы объектов в базах не совпадают.
  2. Проблемы с графикой: Если в печатной форме присутствуют картинки, логотипы, штрихкоды или факсимиле (объекты типа РисунокТабличногоДокумента), сериализация через ЗначениеВСтрокуВнутр может отработать некорректно, потерять графические элементы или завершиться ошибкой преобразования.
  3. Нагрузка на память: Передача огромной XML-подобной строки через COM-соединение при обработке многостраничных документов может приводить к значительному потреблению оперативной памяти и замедлению работы интерфейса.

Способ 2. Передача через временный MXL-файл (Надежный способ)

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

Проанализируем сценарий, когда обе базы (или серверы приложений) имеют доступ к общему сетевому ресурсу или работают на одном физическом сервере:


&НаСервере
Функция ПолучитьТабДокЧерезФайл(ПараметрыПодключения, ИдентификаторДокумента)
    
    COMСоединение = Новый COMОбъект("V83.COMConnector");
    БазаИсточник = COMСоединение.Connect(ПараметрыПодключения);
    
    ДокументСсылкаCOM = БазаИсточник.Документы.РеализацияТоваровУслуг.НайтиПоРеквизиту("Номер", ИдентификаторДокумента);
    
    // Вызываем формирование печатной формы на стороне источника
    ТабДокCOM = БазаИсточник.УчетНДС.ПечатьУниверсальногоПередаточногоДокумента(ДокументСсылкаCOM, Ложь);
    
    // Формируем путь к временному файлу, доступному для обоих серверов
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("mxl");
    
    // Записываем табличный документ в файл на стороне COM-соединения
    ТабДокCOM.Записать(ИмяВременногоФайла, БазаИсточник.ТипФайлаТабличногоДокумента.MXL);
    
    // Читаем файл в локальный табличный документ
    ЛокальныйТабДок = Новый ТабличныйДокумент;
    ЛокальныйТабДок.Прочитать(ИмяВременногоФайла);
    
    // Удаляем временный файл после использования
    Попытка
        УдалитьФайлы(ИмяВременногоФайла);
    Исключение
        // Логируем ошибку удаления, если файл заблокирован процессом
    КонецПопытки;
    
    Возврат ЛокальныйТабДок;
    
КонецФункции

Если серверы приложений баз физически разделены и у них нет общей папки, мы можем передать файл, упаковав его в объект ДвоичныеДанные, который отлично сериализуется через COM-соединение:


// На стороне базы-источника (в COM) преобразуем файл в двоичные данные:
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.MXL);
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);

// Передаем ДвоичныеДанные в базу-приемник через COM-границу.
// В приемнике записываем их обратно на диск и открываем:
ДвоичныеДанныеФайла.Записать(ЛокальныйПутьКФайлу);
ЛокальныйТабДок.Прочитать(ЛокальныйПутьКФайлу);

Проблема контекста внешнего соединения и директив препроцессора

Часто при попытке вызвать типовой метод печати (например, формирование УПД или ТОРГ-12) напрямую из общего модуля конфигурации-источника через COM, разработчики сталкиваются с ошибкой: "Метод объекта не обнаружен" или "Интерактивные операции недоступны".

Выясним причину такого поведения системы:


Способ 3. Лучшее решение без изменения конфигурации — Внешняя обработка-мост

Чтобы обойти ограничения контекста и не вносить изменения в типовую конфигурацию источника (которая должна оставаться на поддержке), применим архитектурный паттерн "Обработка-мост".

Суть метода заключается в создании внешней обработки (с расширением .epf), которая будет выступать в роли изолированного контейнера. Мы поместим её на диск сервера базы-источника. Внутри обработки мы напишем безопасный код формирования печатной формы, который гарантированно не вызовет клиентских методов.

Шаг 1. Создание внешней обработки (ПечатьУПДчерезCOM.epf)

Создадим внешнюю обработку в базе-источнике и напишем в модуле её объекта следующий экспортный метод:


Функция СформироватьИПолучитьУПД(ДокументСсылка, ПутьДляСохранения) Экспорт
    
    // Здесь мы воссоздаем вызовы формирования печатной формы.
    // Если в типовом коде были клиентские вызовы, мы обходим их вручную,
    // подготавливая только структуру данных для печати.
    
    ТабДок = Новый ТабличныйДокумент;
    
    // Например, вызываем серверную функцию формирования макета
    ДанныеДляПечати = УчетНДС.ПолучитьДанныеДляПечатиУПД(ДокументСсылка);
    УчетНДС.ВывестиУПДВТабличныйДокумент(ТабДок, ДанныеДляПечати);
    
    // Записываем полученный результат во временный файл на сервере источника
    ТабДок.Записать(ПутьДляСохранения, ТипФайлаТабличногоДокумента.MXL);
    
    Возврат Истина;
    
КонецФункции

Шаг 2. Вызов внешней обработки из базы-приемника через COM

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


&НаСервере
Функция ПолучитьПечатнуюФормуЧерезОбработкуМост(ПараметрыПодключения, НомерДокумента, ДатаДокумента)
    
    // Подключаемся к COM
    COMСоединение = Новый COMОбъект("V83.COMConnector");
    БазаИсточник = COMСоединение.Connect(ПараметрыПодключения);
    
    // Находим документ-источник
    ДокСсылкаCOM = БазаИсточник.Документы.РеализацияТоваровУслуг.НайтиПоНомеру(НомерДокумента, ДатаДокумента);
    Если ДокСсылкаCOM.Пустая() Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    // Определяем пути к файлам. 
    // Предполагаем, что у серверов есть доступ к общей сетевой папке.
    ПутьКШаблонуОбработки = "\\Server\Share\Bin\ПечатьУПДчерезCOM.epf";
    ПутьКВременномуMXL   = "\\Server\Share\Temp\temp_upd.mxl";
    
    // Программно подключаем внешнюю обработку в сеансе COM
    ОбработкаМост = БазаИсточник.ВнешниеОбработки.Создать(ПутьКШаблонуОбработки);
    
    // Вызываем экспортную функцию обработки
    РезультатВыполнения = ОбработкаМост.СформироватьИПолучитьУПД(ДокСсылкаCOM, ПутьКВременномуMXL);
    
    ЛокальныйТабДок = Новый ТабличныйДокумент;
    
    Если РезультатВыполнения Тогда
        // Читаем сформированный файл в нашей локальной базе
        ЛокальныйТабДок.Прочитать(ПутьКВременномуMXL);
        
        // Удаляем временный файл с диска
        Попытка
            УдалитьФайлы(ПутьКВременномуMXL);
        Исключение
        КонецПопытки;
    КонецЕсли;
    
    Возврат ЛокальныйТабДок;
    
КонецФункции

Преимущества использования "Обработки-моста":

← На главную