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