Как программно передать таблицу значений в реквизит отчета в расширении

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

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

Почему возникает проблема при работе с расширениями?

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

Выясним причину ошибки: общая форма «не видит» реквизиты, добавленные в расширении. В контексте этой формы объект отчета типизируется по метаданным основной конфигурации, где вашего реквизита просто не существует. В результате попытка обращения к Форма.Отчет.МояТаблица приводит к ошибке или пустой ссылке. Единственный надежный способ заставить платформу «увидеть» ваши данные — это явное создание формы отчета непосредственно в расширении.

Способ 1: Создание собственной формы и прямая передача данных

Разберем самый простой и быстрый метод. Если мы создадим форму в расширении, платформа свяжет основной реквизит формы Отчет с объектом метаданных именно из расширения. Это позволит нам обращаться к реквизитам напрямую.

Алгоритм действий следующий:

  1. В расширении у объекта «Отчет» создаем основную форму отчета.
  2. В модуле, откуда вызывается отчет (например, из другой формы или обработки), пишем код открытия.

Пример кода на клиенте:


&НаКлиенте
Процедура ОткрытьОтчетСДанными()
    // Получаем форму отчета из расширения
    ПараметрыФормы = Новый Структура;
    ФормаОтчета = ПолучитьФорму("Отчет.ИмяВашегоОтчета.Форма.ФормаОтчета", ПараметрыФормы);
    
    // Данные можно передать прямо в реквизит, если форма уже создана
    // В данном случае ТЗ_Данные - это ваша подготовленная таблица значений
    // ВАЖНО: На клиенте ТЗ недоступна, поэтому передача должна идти через серверный контекст
    ЗаполнитьРеквизитОтчетаНаСервере(ФормаОтчета);
    
    ФормаОтчета.Открыть();
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьРеквизитОтчетаНаСервере(ФормаОтчета)
    // ТЗ_ДляПередачи - это таблица, сформированная ранее
    ЗначениеВРеквизитФормы(ТЗ_ДляПередачи, "Отчет.ТЗ"); 
КонецПроцедуры

Способ 2: Передача данных через временное хранилище (рекомендуемый)

Рассмотрим более профессиональный подход. Передача больших объемов данных (таких как ТаблицаЗначений) напрямую между формами может быть неэффективной или приводить к ошибкам сериализации. Правильнее использовать временное хранилище.

Посмотрим на пример реализации, когда мы передаем адрес временного хранилища в параметрах открытия формы:

  1. На стороне вызывающего кода: помещаем таблицу в хранилище и передаем адрес в параметрах.
  2. В форме отчета: в обработчике ПриСозданииНаСервере извлекаем данные.

Код вызова:


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

&НаКлиенте
Процедура ВыполнитьОткрытие()
    АдресДанных = ПодготовитьДанныеИПолучитьАдрес();
    
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("АдресТаблицы", АдресДанных);
    
    ОткрытьФорму("Отчет.ИмяОтчета.Форма", ПараметрыОткрытия);
КонецПроцедуры

Теперь проанализируем, что нужно написать в модуле формы отчета в расширении:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("АдресТаблицы") Тогда
        // Извлекаем таблицу из хранилища и записываем в реквизит объекта отчета
        ТаблицаИзХранилища = ПолучитьИзВременногоХранилища(Параметры.АдресТаблицы);
        ЗначениеВРеквизитФормы(ТаблицаИзХранилища, "Отчет.ТЗ");
    КонецЕсли;
КонецПроцедуры

Способ 3: Использование внешнего набора данных в СКД

Если ваша цель — использовать переданную таблицу значений как источник для СКД, то лучше всего использовать механизм ВнешниеНаборыДанных. Это избавляет от необходимости жестко привязывать данные к реквизитам объекта.

Разберем по шагам, как это реализовать в модуле объекта отчета (в расширении), используя предопределенную процедуру ПриКомпоновкеРезультата:


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

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

Важные нюансы и рекомендации

При реализации передачи данных стоит обратить внимание на следующие моменты:

  1. Фоновое выполнение отчетов: В управляемом приложении отчеты часто формируются в фоновом задании. Если вы просто запишете данные в реквизит объекта на сервере при открытии формы, а затем нажмете кнопку «Сформировать», платформа может создать новый экземпляр объекта отчета для фонового задания, и ваш реквизит окажется пустым. Чтобы этого избежать, данные лучше передавать через параметры СКД в виде адреса временного хранилища и извлекать их непосредственно в момент компоновки.
  2. Типизация в СКД: При использовании набора данных «Объект» обязательно опишите все поля таблицы значений в схеме компоновки. Имена колонок в ТаблицаЗначений должны в точности совпадать с именами полей в СКД.
  3. Уникальный идентификатор: Всегда передавайте УникальныйИдентификатор формы при помещении данных в хранилище. Это гарантирует, что данные будут доступны серверным вызовам в контексте этой формы и будут автоматически удалены после её закрытия, не засоряя память сервера.

Подведем итог: для успешной передачи таблицы значений в отчет расширения необходимо создать форму отчета в самом расширении. Это позволит избежать ограничений общей формы и даст возможность программно управлять данными через ПриСозданииНаСервере или механизм внешних наборов данных СКД. Использование временного хранилища является наиболее стабильным методом передачи данных между контекстами клиента и сервера.

← На главную