Как исправить ошибку «Конструктор не найден» при программном создании документов через COM-соединение в 1С:УПП

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

При интеграции различных систем на платформе 1С:Предприятие часто используется механизм COM-соединения. Однако при работе со старыми или сильно доработанными конфигурациями, такими как Управление производственным предприятием (УПП), разработчики сталкиваются со специфическими ошибками. Одна из самых распространенных — Ошибка при вызове метода контекста (записать): Конструктор не найден.

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

Суть проблемы и анализ ситуации

Рассмотрим сценарий: мы пытаемся программно создать документ в базе-приемнике (УПП) из внешней обработки в базе-источнике (ЗУП), используя следующий код:


НовыйИЛ = База.Документы.ИсполнительныйЛист.СоздатьДокумент();  
НовыйИЛ.Дата = ТекущаяДата();
Попытка
    НовыйИЛ.записать();
Исключение
    Сообщить("" + ОписаниеОшибки());
КонецПопытки;

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

Объект Действие (используемый для назначения обработчиков событий кнопкам командных панелей) является чисто клиентским. Когда при записи документа срабатывают подписки на события или код в модуле объекта, который обращается к интерфейсным функциям общего модуля, платформа пытается инициализировать конструктор Новый Действие(...). Поскольку в COM-сеансе этот конструктор недоступен, мы получаем ошибку.

Почему не помогает стандартный флаг Загрузка

Многие программисты справедливо замечают, что для обхода проверок при программной записи следует использовать свойство ОбменДанными.Загрузка = Истина. Посмотрим на пример:


НовыйИЛ = База.Документы.ИсполнительныйЛист.СоздатьДокумент();
НовыйИЛ.ОбменДанными.Загрузка = Истина;
НовыйИЛ.Записать();

Однако в старых конфигурациях этот метод часто не срабатывает. Это происходит потому, что разработчики при кастомизации базы УПП могли вставить вызов общего модуля напрямую в процедуры ПередЗаписью или ПриЗаписи, забыв добавить проверку этого самого флага. Если код в общем модуле вызывается безусловно, то ошибка «Конструктор не найден» все равно прервет выполнение транзакции.

Решение 1: Использование директив компиляции

Самым правильным и надежным способом решения проблемы является модификация кода в базе-приемнике (в нашем случае — в УПП). Проанализируем проблемную строку в общем модуле мОбщегоНазначения. Если там происходит программное создание кнопок или обработка интерфейса, этот блок необходимо обернуть в проверку контекста.

Поскольку старая УПП часто работает в режиме совместимости с 8.1 или использует обычные формы на 8.2, мы должны использовать препроцессор:


#Если Клиент Тогда
    // Здесь располагается код, создающий кнопки и использующий "Новый Действие"
    Кнопка = ЭтаФорма.ЭлементыФормы[ПанельМеню].Кнопки.Добавить("кнУстановить...", ТипКнопкиКоманднойПанели.Действие, "", Новый Действие("...")); 
#КонецЕсли

Важно: Директива #Если Клиент Тогда гарантирует, что данный фрагмент кода будет полностью проигнорирован при выполнении на сервере или в режиме внешнего соединения (COM). Это моментально устранит ошибку «Конструктор не найден».

Решение 2: Проверка режима загрузки данных

Если по каким-то причинам использование директив препроцессора невозможно (например, код должен выполняться в тонком клиенте, но не должен при обмене), необходимо внедрить явную проверку флага ОбменДанными.Загрузка внутри модуля объекта документа ИсполнительныйЛист или в самой процедуре общего модуля.

Разберем, как это реализовать в модуле объекта:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если ОбменДанными.Загрузка Тогда
        Возврат; // Выходим из процедуры, не запуская дополнительные проверки и интерфейсную логику
    КонецЕсли;
    
    // Дальнейший код с вызовом мОбщегоНазначения.ОбновитьИнтерфейс()
КонецПроцедуры

Этот подход считается «золотым стандартом» при разработке механизмов обмена. Он позволяет не только избежать ошибок контекста, но и значительно ускорить загрузку данных, так как отключаются тяжелые алгоритмы проверки бизнес-логики, которые не актуальны при переносе уже готовых данных из другой системы.

Решение 3: Создание серверной обертки в базе-приемнике

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

  1. В конфигурации УПП создается новый Общий модуль с установленными флажками Сервер и Внешнее соединение.
  2. В этом модуле создается экспортная процедура, например, ЗагрузитьИсполнительныйЛист(СтруктураДанных).
  3. Внутри этой процедуры пишется код по созданию документа и заполнению его полей из переданной структуры.
  4. Из внешней базы (ЗУП) через COM вызывается не метод документа Записать(), а именно эта процедура общего модуля.

Пример вызова из ЗУП:


ДанныеДокумента = Новый Структура("Номер, Дата, Физик", "001", ТекущаяДата(), СсылкаНаФизЛицо);
База.мИнтеграцияСервер.ЗагрузитьИсполнительныйЛист(ДанныеДокумента);

Такой метод позволяет платформе более корректно обрабатывать контекст выполнения, так как инициатором записи выступает внутренний серверный код самой базы УПП.

Рекомендации по отладке

Если вы внесли изменения, но ошибка сохраняется, проанализируйте стек вызова. В старых версиях 1С 8.2 ошибка может возникать не в самом документе, а в Подписках на события. Часто в УПП есть подписки на запись любых документов для регистрации изменений в планах обмена или для заполнения свойств и категорий. Проверьте все подписки, связанные с объектом ДокументОбъект.ИсполнительныйЛист, и убедитесь, что в их обработчиках также стоит проверка на ОбменДанными.Загрузка.

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

← На главную