В современной практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача интеграции нескольких внешних обработок. Типичный сценарий: первая обработка загружает данные (например, из файлов Excel), а вторая отвечает за их специфическую печать или дополнительную обработку. Обе они могут быть зарегистрированы в справочнике «Дополнительные отчеты и обработки» (БСП), например, в конфигурации «Бухгалтерия предприятия 3.0».
При попытке вызвать форму второй обработки из кода первой разработчики часто сталкиваются с архитектурными ограничениями управляемого приложения (клиент-серверное разделение) и получают ошибки вида «Неизвестный идентификатор формы». В этой статье мы подробно разберем, почему возникает эта ошибка, как правильно программно подключать внешние обработки, передавать в них параметры и возвращать результат обратно.
В управляемом приложении (УФ) напрямую получить объект формы сторонней обработки через стандартные конструкции метаданных невозможно, если эта обработка не встроена в саму конфигурацию. Когда обработка хранится во внешнем файле или в справочнике «Дополнительные отчеты и обработки», её код необходимо сначала зарегистрировать (подключить) в сеансе работы пользователя.
Ошибка инициализации формы возникает в тот момент, когда разработчик пытается жестко прописать путь к форме, используя её имя из метаданных конфигуратора, например: ОткрытьФорму("ВнешняяОбработка.ИмяИзМетаданных.Форма"). Платформа 1С не знает обработку с таким именем, так как при динамическом подключении через метод ВнешниеОбработки.Подключить() система присваивает обработке уникальное временное имя во избежание конфликтов между сеансами.
Давайте пошагово разберем, как правильно реализовать весь цикл взаимодействия двух внешних обработок.
---
Для того чтобы открыть форму второй внешней обработки, нам нужно извлечь её двоичные данные из справочника, сохранить их во временное хранилище и выполнить регистрацию на сервере. Метод ВнешниеОбработки.Подключить() возвратит нам уникальное имя, которое мы в дальнейшем используем для открытия формы.
Рассмотрим серверную функцию подключения обработки:
&НаСервере
Функция ПодключитьВнешнююОбработкуНаСервере(ИмяОбработкиВСправочнике)
// Находим элемент справочника дополнительных отчетов и обработок по наименованию или имени объекта
СсылкаНаОбработку = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоРеквизиту("ИмяОбъекта", ИмяОбработкиВСправочнике);
Если СсылкаНаОбработку.Пустая() Тогда
ВызватьИсключение "Внешняя обработка '" + ИмяОбработкиВСправочнике + "' не найдена в справочнике!";
КонецЕсли;
// Получаем двоичные данные файла обработки из хранилища значения
ДвоичныеДанныеОбработки = СсылкаНаОбработку.ХранилищеОбработки.Получить();
Если ТипЗнч(ДвоичныеДанныеОбработки) <> Тип("ДвоичныеДанные") Тогда
ВызватьИсключение "Не удалось получить двоичные данные внешней обработки!";
КонецЕсли;
// Помещаем двоичные данные во временное хранилище текущего сеанса
АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеОбработки);
// Подключаем внешнюю обработку и получаем её уникальное системное имя
ИмяПодключения = ВнешниеОбработки.Подключить(АдресВременногоХранилища);
Возврат ИмяПодключения;
КонецФункции
Важное примечание: Если в вашей конфигурации используется Библиотека Стандартных Подсистем (БСП), вам не нужно вручную извлекать двоичные данные из хранилища. Достаточно использовать готовый программный интерфейс общего модуля ДополнительныеОтчетыИОбработки:
&НаСервере
Функция ПодключитьОбработкуЧерезБСП(СсылкаНаОбработку)
Возврат ДополнительныеОтчетыИОбработки.ПодключитьВнешнююОбработку(СсылкаНаОбработку);
КонецФункции
---
После того как мы получили уникальное системное имя подключенной обработки на сервере, мы возвращаемся на клиент и формируем динамический путь для метода ОткрытьФорму(). Путь будет иметь шаблон: "ВнешняяОбработка." + ИмяПодключения + ".Форма.ИмяНужнойФормы".
Проанализируем пример клиентской процедуры вызова:
&НаКлиенте
Процедура ОткрытьФормуВторойОбработки(Команда)
// Шаг 1: Подключаем обработку на сервере и получаем её системное имя
ИмяПодключения = ПодключитьВнешнююОбработкуНаСервере("юи_ВыгрузкаВБухгалтерию");
// Шаг 2: Формируем динамический путь к нужной форме
ИмяФормыДляОткрытия = "ВнешняяОбработка." + ИмяПодключения + ".Форма.ФормаНастроек";
// Шаг 3: Открываем форму
ПараметрыФормы = Новый Структура; // Сюда можно передать начальные параметры
ОткрытьФорму(ИмяФормыДляОткрытия, ПараметрыФормы, ЭтаФорма);
КонецПроцедуры
---
Для того чтобы передать данные (например, отборы для запросов, ссылки на документы или логические флаги) из вызывающей обработки во вторую, используется структура параметров в методе ОткрытьФорму.
Код в вызывающей обработке (первая обработка):
&НаКлиенте
Процедура ЗапускСПараметрами(Команда)
ИмяПодключения = ПодключитьВнешнююОбработкуНаСервере("юи_ВыгрузкаВБухгалтерию");
ИмяФормыДляОткрытия = "ВнешняяОбработка." + ИмяПодключения + ".Форма.ФормаНастроек";
// Заполняем структуру передаваемых параметров
ПараметрыПередачи = Новый Структура;
ПараметрыПередачи.Вставить("ОрганизацияОтбора", Объект.Организация);
ПараметрыПередачи.Вставить("ПериодРегистрации", Объект.Период);
ПараметрыПередачи.Вставить("РежимОтладки", Истина);
ОткрытьФорму(ИмяФормыДляОткрытия, ПараметрыПередачи, ЭтаФорма);
КонецПроцедуры
Код в вызываемой форме (вторая обработка):
В модуле формы второй обработки переданные параметры считываются в обработчике события ПриСозданииНаСервере. Чтобы избежать ошибок при отсутствии параметров, используем безопасный метод Свойство():
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем наличие параметров и применяем их значения
Если Параметры.Свойство("ОрганизацияОтбора") Тогда
// Заполняем реквизит формы значением из параметров
ОтборОрганизация = Параметры.OrganizaciyaOtbola;
КонецЕсли;
Если Параметры.Свойство("РежимОтладки") Тогда
ФлагРежимаОтладки = Параметры.РежимОтладки;
КонецЕсли;
КонецПроцедуры
---
В управляемом приложении мы не можем напрямую прочитать реквизиты или табличные части другой формы, так как они изолированы. Однако платформа предоставляет отличный асинхронный механизм обмена данными — ОписаниеОповещения в связке с закрытием формы.
Если вам нужно вернуть сложные структуры данных (например, таблицу значений или массив настроек), оптимально использовать Временное Хранилище.
Разберем этот процесс по шагам:
Реализация в первой (вызывающей) обработке:
&НаКлиенте
Процедура ОткрытьФормуИПолучитьРезультат(Команда)
ИмяПодключения = ПодключитьВнешнююОбработкуНаСервере("юи_ВыгрузкаВБухгалтерию");
ИмяФормыДляОткрытия = "ВнешняяОбработка." + ИмяПодключения + ".Форма.ФормаНастроек";
// Описываем процедуру, которая выполнится ПОСЛЕ закрытия второй формы
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗакрытияВторойФормы", ЭтаФорма);
// Открываем форму модально по отношению к владельцу
ОткрытьФорму(ИмяФормыДляОткрытия, , ЭтаФорма, , , , ОписаниеОповещения, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗакрытияВторойФормы(РезультатВыбора, ДополнительныеПараметры) Экспорт
// Проверяем, вернула ли закрытая форма адрес хранилища
Если ЗначениеЗаполнено(РезультатВыбора) Тогда
// Переходим на сервер для извлечения данных
ОбработатьПолученныеДанныеНаСервере(РезультатВыбора);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ОбработатьПолученныеДанныеНаСервере(АдресХранилища)
// Получаем структуру данных из временного хранилища по переданному адресу
СтруктураРезультата = ПолучитьИзВременногоХранилища(АдресХранилища);
Если ТипЗнч(СтруктураРезультата) = Тип("Структура") Тогда
// Обрабатываем полученную таблицу настроек или параметры
ТаблицаВыгрузки = СтруктураРезультата.ТаблицаДокументов;
ДополнительныеНастройки = СтруктураРезультата.ПараметрыПечати;
// Выполняем дальнейшую бизнес-логику первой обработки...
КонецЕсли;
КонецПроцедуры
Реализация во второй (вызываемой) обработке:
&НаКлиенте
Процедура КомандаОК(Команда)
// Помещаем данные во временное хранилище на сервере
АдресРезультата = ПоместитьРезультатВХранилищеНаСервере();
// Закрываем форму и возвращаем адрес в качестве результата выбора
Закрыть(АдресРезультата);
КонецПроцедуры
&НаСервере
Функция ПоместитьРезультатВХранилищеНаСервере()
// Формируем структуру сложных данных, которую невозможно напрямую передать на клиент
СтруктураРезультата = Новый Структура;
// Преобразуем реквизит формы (табличную часть) обратно в объектную Таблицу Значений
ТаблицаДляПередачи = РеквизитФормыВЗначение("ТаблицаНастроек");
СтруктураРезультата.Вставить("ТаблицаДокументов", ТаблицаДляПередачи);
СтруктураРезультата.Вставить("ПараметрыПечати", КонстантыНастройкиПечати);
// Важно: Привязываем адрес к Уникальному Идентификатору формы, чтобы данные жили до закрытия сеанса
Возврат ПоместитьВоВременноеХранилище(СтруктураРезультата, УникальныйИдентификатор);
КонецФункции
---
Мы подробно проанализировали механизм взаимодействия двух внешних обработок на управляемых формах 1С. Использование жесткого кодирования имен метаданных приводит к ошибкам идентификации форм, поэтому наиболее надежным и современным решением является:
ВнешниеОбработки.Подключить() (или через API БСП).ОткрытьФорму().ОписаниеОповещения и буферизации данных через ВременноеХранилище.