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