Как программно настроить СКД: отключаем итоги, добавляем группу ИЛИ в отбор и правильно инициализируем компоновщик

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

Разработка отчетов и обработок выгрузки данных на базе Системы компоновки данных (СКД) в 1С — это мощный инструмент в арсенале любого разработчика. Однако при программной настройке СКД часто возникают неочевидные проблемы: то в выгружаемую таблицу попадают лишние строки итогов, то не удается построить сложную иерархию отборов, а то и вовсе платформа выбрасывает ошибку «Несоответствие типов» при попытке добавить новую группировку. В этой статье мы подробно разберем, как решать подобные проблемы программно, рассмотрим нюансы инициализации компоновщика настроек и научимся оптимизировать выгрузку результатов в формат JSON.

Решение 1. Как программно отключить вывод итоговых строк в СКД

Когда мы разрабатываем отчет для пользователя, итоговые строки внизу таблицы или групп необходимы для наглядности. Но когда СКД используется в качестве источника данных для интеграции (например, для последующей выгрузки в JSON, XML или отправки по API), итоговые строки только мешают, так как они дублируют данные и ломают структуру обмена.

Попытка обратиться напрямую к элементам коллекции параметров вывода через квадратные скобки по имени настройки (например, ПараметрыВывода.Элементы["РасположениеИтогов"]) вызывает ошибку отсутствия поля объекта. Выясним причину: коллекция параметров вывода является специализированным объектом, и обращаться к ней нужно через предназначенные для этого методы.

Чтобы программно отключить общие итоги в СКД, воспользуемся методом УстановитьЗначениеПараметра у коллекции параметров вывода настроек компоновки. Рассмотрим рабочий пример кода:


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

// Отключаем вертикальное расположение общих итогов
Настройки.ПараметрыВывода.УстановитьЗначениеПараметра("ВертикальноеРасположениеОбщихИтогов", РасположениеИтоговКомпоновкиДанных.Нет);

// Отключаем горизонтальное расположение общих итогов
Настройки.ПараметрыВывода.УстановитьЗначениеПараметра("ГоризонтальноеРасположениеОбщихИтогов", РасположениеИтоговКомпоновкиДанных.Нет);

// Отключаем расположение итогов в группировках
Настройки.ПараметрыВывода.УстановитьЗначениеПараметра("РасположениеИтогов", РасположениеИтоговКомпоновкиДанных.Нет);

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

Решение 2. Программное добавление группы «ИЛИ» в отборы компоновки

Часто требуется ограничить выборку данных сложным условием. Простые отборы по умолчанию объединяются логическим «И». Но что делать, если нужно реализовать условие вида (Склад = Склад1 ИЛИ Склад = Склад2)? Для этого необходимо программно создать группу элементов отбора с типом группы ГруппаИли.

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


// 1. Создаем группу ИЛИ в коллекции элементов отбора
ГруппаИЛИ = Настройки.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИЛИ.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИли;
ГруппаИЛИ.Использование = Истина;

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

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

Обратите внимание, что мы добавляем новые элементы методом ГруппаИЛИ.Элементы.Добавить(), а не через Настройки.Отбор.Элементы.Добавить(). Это обеспечивает правильную вложенность условий.

Решение 3. Тонкости инициализации Компоновщика настроек и устранение ошибки «Несоответствие типов»

При программной работе в контексте управляемой формы (например, в модуле формы обработки) попытка напрямую изменить структуру компоновщика настроек, добавленного в реквизиты объекта или формы, может завершиться аварийно с ошибкой «Несоответствие типов» при выполнении метода Настройки.Structure.Add() (или Структура.Добавить()).

Выясним причину этой проблемы. Она кроется в особенностях клиент-серверного взаимодействия платформы 1С:

  1. Объект СхемаКомпоновкиДанных не может существовать на клиенте, так как он не сериализуется.
  2. При передаче контекста формы с сервера на клиент и обратно источник доступных настроек компоновщика, инициализированный напрямую объектом схемы, «теряет» связь с описанием метаданных и полей схемы.
  3. В результате коллекция настроек переходит в некорректное состояние, при котором методы изменения структуры начинают выдавать ошибку несоответствия типов, либо в интерактивном режиме пользователь перестает видеть доступные поля компоновки.

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


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

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

Решение 4. Эффективная выгрузка результатов СКД в JSON

Рассмотрим, как оптимизировать процесс преобразования данных СКД в формат JSON. На практике часто сначала выгружают результат СКД в промежуточную ТаблицуЗначений, а затем преобразуют её. Однако прямая сериализация таблицы значений в JSON встроенными средствами платформы не поддерживается. Для этого приходится обходить таблицу в цикле и собирать массив структур.

Посмотрим на пример классической сериализации через промежуточную таблицу значений:


// 1. Выводим данные в Таблицу Значений
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СКД, Настройки,,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

ТаблицаРезультата = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(ТаблицаРезультата);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

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

// 3. Записываем в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МассивОбъектов);
РезультатJSON = ЗаписьJSON.Закрыть();

Важная рекомендация по оптимизации: Если выгружаемый отчет содержит десятки тысяч строк, создание промежуточной таблицы значений в памяти сервера нагрузит оперативную память дважды. Чтобы этого избежать, используйте потоковый вывод: обходите результаты компоновки построчно через ПроцессорКомпоновки.Следующий() и сразу же пишите данные в поток ЗаписьJSON. Это существенно ускорит выполнение операции и снизит потребление памяти сервера.

← На главную