Как программно сформировать отчет на СКД и настроить группировки из кода?

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

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

Базовый алгоритм программного вывода отчета

Процесс компоновки данных в 1С состоит из последовательного взаимодействия нескольких ключевых объектов платформы. Разберем стандартную схему выполнения:

  1. Схема компоновки данных: содержит описание наборов данных, запросов, связей, параметров и доступных полей (СхемаКомпоновкиДанных).
  2. Настройки компоновки: определяют, какие именно поля выбраны, какие установлены отборы, параметры и группировки (КомпоновщикНастроек).
  3. Компоновщик макета: объединяет схему и настройки, создавая исполняемый макет (КомпоновщикМакетаКомпоновкиДанных, результат — МакетКомпоновкиДанных).
  4. Процессор компоновки: выполняет запросы к базе данных и производит расчет итогов по макету (ПроцессорКомпоновкиДанных).
  5. Процессор вывода: построчно отрисовывает готовый результат в табличный документ или дерево значений (ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент).

Посмотрим на пример классической процедуры формирования отчета на сервере:


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

Почему отчет формируется пустым: основные причины

Проанализируем распространенные ошибки, из-за которых после нажатия кнопки результат не выводится на экран:

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

Программное создание структуры группировок

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


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

Корректная установка параметров в пользовательских настройках

Чтобы гарантировать применение переданных параметров при использовании стандартного компоновщика отчета, рекомендуется менять их значение напрямую в пользовательских настройках:


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

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

← На главную