При интеграции различных систем на платформе 1С:Предприятие часто используется механизм COM-соединения. Однако при работе со старыми или сильно доработанными конфигурациями, такими как Управление производственным предприятием (УПП), разработчики сталкиваются со специфическими ошибками. Одна из самых распространенных — Ошибка при вызове метода контекста (записать): Конструктор не найден.
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем механизмы работы платформы в неинтерактивном режиме и найдем способы решения, которые позволят корректно переносить данные, например, исполнительные листы из ЗУП в УПП.
Рассмотрим сценарий: мы пытаемся программно создать документ в базе-приемнике (УПП) из внешней обработки в базе-источнике (ЗУП), используя следующий код:
НовыйИЛ = База.Документы.ИсполнительныйЛист.СоздатьДокумент();
НовыйИЛ.Дата = ТекущаяДата();
Попытка
НовыйИЛ.записать();
Исключение
Сообщить("" + ОписаниеОшибки());
КонецПопытки;
При выполнении метода записать() система выдает исключение, указывающее на строку в общем модуле, где происходит попытка создания объекта Действие или обращение к элементам формы. Выясним причину: COM-соединение создает сеанс, который является неинтерактивным. В таком сеансе отсутствует «клиентская» часть в привычном понимании — нет интерфейса, нет форм и, соответственно, недоступны многие типы данных, связанные с визуализацией.
Объект Действие (используемый для назначения обработчиков событий кнопкам командных панелей) является чисто клиентским. Когда при записи документа срабатывают подписки на события или код в модуле объекта, который обращается к интерфейсным функциям общего модуля, платформа пытается инициализировать конструктор Новый Действие(...). Поскольку в COM-сеансе этот конструктор недоступен, мы получаем ошибку.
Многие программисты справедливо замечают, что для обхода проверок при программной записи следует использовать свойство ОбменДанными.Загрузка = Истина. Посмотрим на пример:
НовыйИЛ = База.Документы.ИсполнительныйЛист.СоздатьДокумент();
НовыйИЛ.ОбменДанными.Загрузка = Истина;
НовыйИЛ.Записать();
Однако в старых конфигурациях этот метод часто не срабатывает. Это происходит потому, что разработчики при кастомизации базы УПП могли вставить вызов общего модуля напрямую в процедуры ПередЗаписью или ПриЗаписи, забыв добавить проверку этого самого флага. Если код в общем модуле вызывается безусловно, то ошибка «Конструктор не найден» все равно прервет выполнение транзакции.
Самым правильным и надежным способом решения проблемы является модификация кода в базе-приемнике (в нашем случае — в УПП). Проанализируем проблемную строку в общем модуле мОбщегоНазначения. Если там происходит программное создание кнопок или обработка интерфейса, этот блок необходимо обернуть в проверку контекста.
Поскольку старая УПП часто работает в режиме совместимости с 8.1 или использует обычные формы на 8.2, мы должны использовать препроцессор:
#Если Клиент Тогда
// Здесь располагается код, создающий кнопки и использующий "Новый Действие"
Кнопка = ЭтаФорма.ЭлементыФормы[ПанельМеню].Кнопки.Добавить("кнУстановить...", ТипКнопкиКоманднойПанели.Действие, "", Новый Действие("..."));
#КонецЕсли
Важно: Директива #Если Клиент Тогда гарантирует, что данный фрагмент кода будет полностью проигнорирован при выполнении на сервере или в режиме внешнего соединения (COM). Это моментально устранит ошибку «Конструктор не найден».
Если по каким-то причинам использование директив препроцессора невозможно (например, код должен выполняться в тонком клиенте, но не должен при обмене), необходимо внедрить явную проверку флага ОбменДанными.Загрузка внутри модуля объекта документа ИсполнительныйЛист или в самой процедуре общего модуля.
Разберем, как это реализовать в модуле объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат; // Выходим из процедуры, не запуская дополнительные проверки и интерфейсную логику
КонецЕсли;
// Дальнейший код с вызовом мОбщегоНазначения.ОбновитьИнтерфейс()
КонецПроцедуры
Этот подход считается «золотым стандартом» при разработке механизмов обмена. Он позволяет не только избежать ошибок контекста, но и значительно ускорить загрузку данных, так как отключаются тяжелые алгоритмы проверки бизнес-логики, которые не актуальны при переносе уже готовых данных из другой системы.
В ситуациях, когда база УПП крайне нестабильна или содержит слишком много связанных вызовов, попытки прямой записи объекта через COM извне могут превратиться в бесконечную борьбу с ошибками контекста. В этом случае мы рекомендуем рассмотреть архитектурный подход «обертки».
Сервер и Внешнее соединение.ЗагрузитьИсполнительныйЛист(СтруктураДанных).Записать(), а именно эта процедура общего модуля.Пример вызова из ЗУП:
ДанныеДокумента = Новый Структура("Номер, Дата, Физик", "001", ТекущаяДата(), СсылкаНаФизЛицо);
База.мИнтеграцияСервер.ЗагрузитьИсполнительныйЛист(ДанныеДокумента);
Такой метод позволяет платформе более корректно обрабатывать контекст выполнения, так как инициатором записи выступает внутренний серверный код самой базы УПП.
Если вы внесли изменения, но ошибка сохраняется, проанализируйте стек вызова. В старых версиях 1С 8.2 ошибка может возникать не в самом документе, а в Подписках на события. Часто в УПП есть подписки на запись любых документов для регистрации изменений в планах обмена или для заполнения свойств и категорий. Проверьте все подписки, связанные с объектом ДокументОбъект.ИсполнительныйЛист, и убедитесь, что в их обработчиках также стоит проверка на ОбменДанными.Загрузка.
Помните, что при работе через COM-соединение крайне важно разделять логику управления данными и логику управления интерфейсом. Соблюдение этих правил позволит вам создавать стабильные интеграции даже с самыми древними и доработанными конфигурациями.