Часто перед разработчиками встает задача предоставить пользователю возможность открывать отчет непосредственно из документа, причем отчет должен быть сразу заполнен данными из этого документа. Например, из документа "Реализация товаров и услуг" нужно открыть отчет по продажам, который будет отфильтрован по дате, складу и номенклатуре из табличной части этого документа. Давайте разберем, как это реализовать.
Проблема автора темы заключается в том, что он создал команду для открытия отчета, но не понимает, как из этой команды получить доступ к реквизитам документа и передать их в открываемую форму отчета. Исходный код выглядит так:
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
ОткрытьФорму("Отчет.МойОтчет.ФормаОбъекта");
КонецПроцедуры
Проанализируем основные способы решения этой задачи, от самого простого к более универсальному.
Это самый простой и распространенный метод, особенно если команда вызова отчета находится непосредственно в форме документа. В этом случае у нас есть прямой доступ ко всем реквизитам формы через объект Объект.
Суть метода заключается в том, чтобы собрать все необходимые данные в специальный объект типа Структура и передать его в третьем параметре функции ОткрытьФорму(). На стороне отчета, в обработчике события ПриСозданииНаСервере, мы эту структуру получим и используем для установки параметров.
Шаг 1. Модифицируем код вызова отчета на стороне документа.
В обработчике команды на клиенте нам нужно собрать все данные: дату, склад и список номенклатуры из табличной части. Затем мы создаем структуру, где ключи — это имена параметров, которые "ожидает" наш отчет, а значения — это собранные нами данные.
&НаКлиенте
Процедура ОткрытьОтчет(Команда)
// 1. Создаем структуру для передачи параметров
ПараметрыОткрытия = Новый Структура;
// 2. Заполняем простые параметры (дата, склад)
ПараметрыОткрытия.Вставить("ДатаОтчета", Объект.Дата);
ПараметрыОткрытия.Вставить("СкладОтчета", Объект.Склад);
// 3. Собираем данные из табличной части в СписокЗначений
СписокНоменклатуры = Новый СписокЗначений;
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
СписокНоменклатуры.Добавить(СтрокаТЧ.Номенклатура);
КонецЦикла;
ПараметрыОткрытия.Вставить("СписокНоменклатуры", СписокНоменклатуры);
// 4. Открываем форму отчета с передачей параметров
ОткрытьФорму("Отчет.МойОтчет.Форма", ПараметрыОткрытия);
КонецПроцедуры
Важный момент: Обратите внимание, что мы используем ОткрытьФорму("Отчет.МойОтчет.Форма", ...), а не "Отчет.МойОтчет.ФормаОбъекта". Форма объекта предназначена для настройки самого отчета как объекта конфигурации, а нам нужна основная форма, где пользователь работает с настройками и формирует его.
Шаг 2. Принимаем и обрабатываем параметры в форме отчета.
Теперь в модуле формы отчета нам нужно получить переданные данные. Для этого используется серверный обработчик события ПриСозданииНаСервере. Переданная нами структура будет доступна в свойстве формы Параметры.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, были ли переданы параметры при открытии формы
Если Параметры.Свойство("ДатаОтчета") Тогда
// Получаем доступ к компоновщику настроек отчета
КомпоновщикНастроек = Отчет.КомпоновщикНастроек;
// Устанавливаем значение параметра "Период"
// Важно: стандартный параметр "Период" в СКД - это тип СтандартныйПериод
// Он содержит ДатуНачала и ДатуОкончания.
НастройкаПериода = КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Период"));
Если НастройкаПериода <> Неопределено Тогда
НастройкаПериода.Значение.ДатаНачала = НачалоДня(Параметры.ДатаОтчета);
НастройкаПериода.Значение.ДатаОкончания = КонецДня(Параметры.ДатаОтчета);
НастройкаПериода.Использование = Истина;
КонецЕсли;
// Устанавливаем отбор по складу
ЭлементОтбораСклад = КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораСклад.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад");
ЭлементОтбораСклад.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбораСклад.ПравоеЗначение = Параметры.СкладОтчета;
ЭлементОтбораСклад.Использование = Истина;
// Устанавливаем отбор по списку номенклатуры
Если Параметры.Свойство("СписокНоменклатуры") И ТипЗнч(Параметры.СписокНоменклатуры) = Тип("СписокЗначений") Тогда
ЭлементОтбораНоменклатура = КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораНоменклатура.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Номенклатура");
ЭлементОтбораНоменклатура.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбораНоменклатура.ПравоеЗначение = Параметры.СписокНоменклатуры;
ЭлементОтбораНоменклатура.Использование = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
После выполнения этого кода форма отчета откроется с уже установленными отборами, и пользователю останется только нажать кнопку "Сформировать".
Этот подход считается более правильным с точки зрения архитектуры. Его суть в том, чтобы не передавать в отчет "сырые" данные, а передать только ссылку на документ-источник. А уже сам отчет, получив ссылку, решает, какие данные ему нужны, и самостоятельно их получает.
Преимущества:
Шаг 1. Код вызова в форме документа.
Код вызова значительно упрощается. Нам нужно передать только один параметр — ссылку на текущий документ.
&НаКлиенте
Процедура ОткрытьОтчет(Команда)
ПараметрыОткрытия = Новый Структура("ИсточникДанных", Объект.Ссылка);
ОткрытьФорму("Отчет.МойОтчет.Форма", ПараметрыОткрытия);
КонецПроцедуры
Если ваша команда является параметризуемой и размещена, например, в командной панели формы, то система автоматически передаст ссылку на объект в параметр ПараметрКоманды. Тогда код будет еще проще:
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
ПараметрыОткрытия = Новый Структура("ИсточникДанных", ПараметрКоманды);
ОткрытьФорму("Отчет.МойОтчет.Форма", ПараметрыОткрытия, ПараметрыВыполненияКоманды.Источник);
КонецПроцедуры
Шаг 2. Получение данных в форме отчета.
В обработчике ПриСозданииНаСервере мы проверяем наличие параметра ИсточникДанных. Если он есть, мы получаем по этой ссылке все необходимые реквизиты. Важно: чтобы не загружать весь объект документа методом ПолучитьОбъект(), что может быть неоптимально, лучше получить нужные данные одним запросом.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ИсточникДанных") И ЗначениеЗаполнено(Параметры.ИсточникДанных) Тогда
СсылкаНаДокумент = Параметры.ИсточникДанных;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДокументРеализации.Дата,
| ДокументРеализации.Склад,
| ДокументРеализации.Товары.(
| Номенклатура
| )
|ИЗ
| Документ.РеализацияТоваровУслуг КАК ДокументРеализации
|ГДЕ
| ДокументРеализации.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ДатаДокумента = Выборка.Дата;
СкладДокумента = Выборка.Склад;
СписокНоменклатуры = Выборка.Товары.Выгрузить().ВыгрузитьКолонку("Номенклатура");
// Далее идет код установки параметров и отборов,
// аналогичный тому, что был в Способе 1,
// но теперь мы используем переменные ДатаДокумента, СкладДокумента и СписокНоменклатуры
// ... код установки параметров компоновщика ...
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот способ, хоть и требует написания запроса, является более профессиональным и предпочтительным для сложных, развивающихся систем.
Мы рассмотрели два основных подхода к решению задачи. Выбор между ними зависит от конкретной ситуации:
Вне зависимости от выбранного способа, ключевым является понимание механизма: подготовка данных на клиенте, передача их через параметр функции ОткрытьФорму и их обработка на сервере в событии ПриСозданииНаСервере формы отчета для настройки КомпоновщикаНастроек.