Как запустить отчет из документа и передать в него параметры (Дату, Склад, данные из табличной части)?

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

Часто перед разработчиками встает задача предоставить пользователю возможность открывать отчет непосредственно из документа, причем отчет должен быть сразу заполнен данными из этого документа. Например, из документа "Реализация товаров и услуг" нужно открыть отчет по продажам, который будет отфильтрован по дате, складу и номенклатуре из табличной части этого документа. Давайте разберем, как это реализовать.

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


&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
    ОткрытьФорму("Отчет.МойОтчет.ФормаОбъекта");
КонецПроцедуры

Проанализируем основные способы решения этой задачи, от самого простого к более универсальному.

Способ 1. Прямая передача параметров через структуру

Это самый простой и распространенный метод, особенно если команда вызова отчета находится непосредственно в форме документа. В этом случае у нас есть прямой доступ ко всем реквизитам формы через объект Объект.

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

Шаг 1. Модифицируем код вызова отчета на стороне документа.

В обработчике команды на клиенте нам нужно собрать все данные: дату, склад и список номенклатуры из табличной части. Затем мы создаем структуру, где ключи — это имена параметров, которые "ожидает" наш отчет, а значения — это собранные нами данные.


&НаКлиенте
Процедура ОткрытьОтчет(Команда)

    // 1. Создаем структуру для передачи параметров
    ПараметрыОткрытия = Новый Структура;

    // 2. Заполняем простые параметры (дата, склад)
    ПараметрыОткрытия.Вставить("ДатаОтчета", Объект.Дата);
    ПараметрыОткрытия.Вставить("СкладОтчета", Объект.Склад);

    // 3. Собираем данные из табличной части в СписокЗначений
    СписокНоменклатуры = Новый СписокЗначений;
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        СписокНоменклатуры.Добавить(СтрокаТЧ.Номенклатура);
    КонецЦикла; 
    
    ПараметрыОткрытия.Вставить("СписокНоменклатуры", СписокНоменклатуры);

    // 4. Открываем форму отчета с передачей параметров
    ОткрытьФорму("Отчет.МойОтчет.Форма", ПараметрыОткрытия); 
    
КонецПроцедуры

Важный момент: Обратите внимание, что мы используем ОткрытьФорму("Отчет.МойОтчет.Форма", ...), а не "Отчет.МойОтчет.ФормаОбъекта". Форма объекта предназначена для настройки самого отчета как объекта конфигурации, а нам нужна основная форма, где пользователь работает с настройками и формирует его.

Шаг 2. Принимаем и обрабатываем параметры в форме отчета.

Теперь в модуле формы отчета нам нужно получить переданные данные. Для этого используется серверный обработчик события ПриСозданииНаСервере. Переданная нами структура будет доступна в свойстве формы Параметры.


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    // Проверяем, были ли переданы параметры при открытии формы
    Если Параметры.Свойство("ДатаОтчета") Тогда
        
        // Получаем доступ к компоновщику настроек отчета
        КомпоновщикНастроек = Отчет.КомпоновщикНастроек;
        
        // Устанавливаем значение параметра "Период"
        // Важно: стандартный параметр "Период" в СКД - это тип СтандартныйПериод
        // Он содержит ДатуНачала и ДатуОкончания.
        НастройкаПериода = КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Период"));
        Если НастройкаПериода <> Неопределено Тогда
            НастройкаПериода.Значение.ДатаНачала = НачалоДня(Параметры.ДатаОтчета);
            НастройкаПериода.Значение.ДатаОкончания = КонецДня(Параметры.ДатаОтчета);
            НастройкаПериода.Использование = Истина;
        КонецЕсли;

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

        // Устанавливаем отбор по списку номенклатуры
        Если Параметры.Свойство("СписокНоменклатуры") И ТипЗнч(Параметры.СписокНоменклатуры) = Тип("СписокЗначений") Тогда
            ЭлементОтбораНоменклатура = КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
            ЭлементОтбораНоменклатура.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных("Номенклатура");
            ЭлементОтбораНоменклатура.ВидСравнения   = ВидСравненияКомпоновкиДанных.ВСписке;
            ЭлементОтбораНоменклатура.ПравоеЗначение = Параметры.СписокНоменклатуры;
            ЭлементОтбораНоменклатура.Использование  = Истина;
        КонецЕсли;
        
    КонецЕсли;

КонецПроцедуры

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

Способ 2. Передача ссылки на документ

Этот подход считается более правильным с точки зрения архитектуры. Его суть в том, чтобы не передавать в отчет "сырые" данные, а передать только ссылку на документ-источник. А уже сам отчет, получив ссылку, решает, какие данные ему нужны, и самостоятельно их получает.

Преимущества:

  1. Независимость отчета. Отчет не зависит от того, какая форма его вызывает и какие данные она решила ему передать. Вся логика получения данных инкапсулирована внутри отчета.
  2. Гибкость. Если в будущем отчету понадобятся дополнительные данные из документа (например, контрагент), вам не придется менять код во всех формах, откуда он вызывается. Достаточно будет доработать только код в самом отчете.

Шаг 1. Код вызова в форме документа.

Код вызова значительно упрощается. Нам нужно передать только один параметр — ссылку на текущий документ.


&НаКлиенте
Процедура ОткрытьОтчет(Команда)

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

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


&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)

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

Шаг 2. Получение данных в форме отчета.

В обработчике ПриСозданииНаСервере мы проверяем наличие параметра ИсточникДанных. Если он есть, мы получаем по этой ссылке все необходимые реквизиты. Важно: чтобы не загружать весь объект документа методом ПолучитьОбъект(), что может быть неоптимально, лучше получить нужные данные одним запросом.


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Если Параметры.Свойство("ИсточникДанных") И ЗначениеЗаполнено(Параметры.ИсточникДанных) Тогда
        
        СсылкаНаДокумент = Параметры.ИсточникДанных;
        
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ
            |    ДокументРеализации.Дата,
            |    ДокументРеализации.Склад,
            |    ДокументРеализации.Товары.(
            |        Номенклатура
            |    )
            |ИЗ
            |    Документ.РеализацияТоваровУслуг КАК ДокументРеализации
            |ГДЕ
            |    ДокументРеализации.Ссылка = &Ссылка";
        
        Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
        
        Выборка = Запрос.Выполнить().Выбрать();
        Если Выборка.Следующий() Тогда
            
            ДатаДокумента = Выборка.Дата;
            СкладДокумента = Выборка.Склад;
            СписокНоменклатуры = Выборка.Товары.Выгрузить().ВыгрузитьКолонку("Номенклатура");
            
            // Далее идет код установки параметров и отборов,
            // аналогичный тому, что был в Способе 1,
            // но теперь мы используем переменные ДатаДокумента, СкладДокумента и СписокНоменклатуры
            
            // ... код установки параметров компоновщика ...

        КонецЕсли;
        
    КонецЕсли;

КонецПроцедуры

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

Выводы

Мы рассмотрели два основных подхода к решению задачи. Выбор между ними зависит от конкретной ситуации:

Вне зависимости от выбранного способа, ключевым является понимание механизма: подготовка данных на клиенте, передача их через параметр функции ОткрытьФорму и их обработка на сервере в событии ПриСозданииНаСервере формы отчета для настройки КомпоновщикаНастроек.

← На главную