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