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