При разработке отчетов, обработок или интерфейсов в 1С часто возникает задача преобразования данных из одной структуры в другую. Одной из таких распространенных задач является преобразование плоской таблицы значений в дерево значений. Это особенно актуально, когда нам необходимо отобразить иерархические данные, например, когда документ содержит данные шапки и табличной части, и мы хотим представить их в виде дерева: данные шапки — верхний уровень, а строки табличной части — подчиненный уровень.
В этом руководстве мы подробно рассмотрим несколько подходов к решению этой задачи, учитывая различные исходные данные и требования к сложности иерархии.
Наиболее гибкий и контролируемый способ преобразования таблицы значений в дерево значений — это программное создание объекта ДеревоЗначений и построчное заполнение его данными. Этот метод позволяет нам определить любую сложность иерархии, указать, какие строки станут родительскими, а какие — подчиненными.
Создаем объект ДеревоЗначений и определяем его колонки.
Прежде всего, нам необходимо создать новый экземпляр ДереваЗначений. Затем мы добавляем в него колонки, которые будут соответствовать полям из нашей исходной таблицы значений и дополнительным данным шапки документа, если таковые имеются.
ДЗ = Новый ДеревоЗначений;
ДЗ.Колонки.Добавить("НомерДокумента");
ДЗ.Колонки.Добавить("ДатаДокумента");
ДЗ.Колонки.Добавить("ОрганизацияПокупатель");
ДЗ.Колонки.Добавить("Номенклатура");
ДЗ.Колонки.Добавить("Количество");
ДЗ.Колонки.Добавить("Цена");
ДЗ.Колонки.Добавить("Сумма");
// Добавьте все необходимые колонки, соответствующие полям шапки и ТЧ
Добавляем корневую строку для данных шапки документа.
Согласно нашей задаче, данные шапки документа (например, номер, дата, организация покупателя) должны составлять первый уровень дерева. Мы создаем новую строку в корне ДереваЗначений и заполняем ее соответствующими значениями.
// Предположим, у нас есть ОбъектДокумента (например, РТиУ) или структура с данными шапки
// Например: ДокументСсылкаИлиПрямСамОбъект - это ссылка на документ или сам объект документа
Шапка = ДЗ.Строки.Добавить();
ЗаполнитьЗначенияСвойств(Шапка, ДокументСсылкаИлиПрямСамОбъект, "НомерДокумента,ДатаДокумента,Контрагент");
// Если в ДокументСсылкаИлиПрямСамОбъект есть Контрагент,
// а в ДЗ.Колонки есть ОрганизацияПокупатель, то можно вручную присвоить:
// Шапка.ОрганизацияПокупатель = ДокументСсылкаИлиПрямСамОбъект.Контрагент;
// Для примера, если у нас есть структура с данными шапки:
// СтруктураШапки = Новый Структура("НомерДокумента, ДатаДокумента, ОрганизацияПокупатель", "РТ001", Дата("20230101"), "ООО Рога и Копыта");
// ЗаполнитьЗначенияСвойств(Шапка, СтруктураШапки);
// Пример заполнения вручную, если данных много и они не соответствуют напрямую свойствам:
// Шапка.НомерДокумента = ДокументСсылкаИлиПрямСамОбъект.Номер;
// Шапка.ДатаДокумента = ДокументСсылкаИлиПрямСамОбъект.Дата;
// Шапка.ОрганизацияПокупатель = ДокументСсылкаИлиПрямСамОбъект.Контрагент;
Метод ЗаполнитьЗначенияСвойств() очень удобен, когда имена свойств источника совпадают с именами колонок приемника. Если имена отличаются или нужно выборочное заполнение, мы можем присваивать значения колонкам строки вручную.
Итерируем по строкам исходной таблицы значений и добавляем их как дочерние элементы.
Далее мы обходим каждую строку нашей исходной таблицы значений (например, табличной части документа) и для каждой строки создаем дочернюю строку к нашей корневой строке (шапке). Заполняем свойства дочерней строки данными из текущей строки таблицы значений.
// Предположим, ТЧДокумента - это ТаблицаЗначений, полученная из документа или Excel
// Например: ТЧДокумента = ДокументСсылкаИлиПрямСамОбъект.Товары;
Для Каждого Стр Из ТЧДокумента Цикл
СтрокаТЧ = Шапка.Строки.Добавить();
ЗаполнитьЗначенияСвойств(СтрокаТЧ, Стр, "Номенклатура,Количество,Цена,Сумма");
// Здесь указываем только те колонки, которые относятся к табличной части
// Пример заполнения вручную:
// СтрокаТЧ.Номенклатура = Стр.Номенклатура;
// СтрокаТЧ.Количество = Стр.Количество;
// СтрокаТЧ.Цена = Стр.Цена;
// СтрокаТЧ.Сумма = Стр.Сумма;
КонецЦикла;
Используем полученное дерево значений.
После выполнения этих шагов мы получим объект ДеревоЗначений, где первый уровень будет представлять данные шапки, а второй уровень — строки табличной части, связанные с этой шапкой. Это дерево значений может быть использовано для отображения в форме (например, в элементе формы Дерево) или для дальнейшей обработки. В качестве альтернативного способа визуализации связи шапки и табличной части в интерфейсе можно использовать решение для связывания главной и подчиненной таблиц на управляемой форме.
// Пример использования: Показать полученное дерево
// Если ДеревоЗначений является реквизитом формы:
// Элементы.ДеревоНаФорме.Значение = ДЗ;
// Или для отладки:
// ДЗ.Показать();
Если наши данные изначально могут быть получены с помощью запроса, то мы можем использовать построитель запросов. Этот инструмент позволяет нам преобразовать результат запроса в дерево значений, автоматически формируя иерархию на основе группировок, определенных в запросе.
Формируем запрос с секцией ИТОГИ ПО.
Ключевым моментом здесь является использование секции ИТОГИ ПО в нашем запросе. Именно она определяет иерархию будущего дерева. Поля, по которым мы группируем итоги, станут узлами верхнего уровня в дереве.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Документы.Ссылка КАК СсылкаДокумента,
| Документы.Номер КАК НомерДокумента,
| Документы.Дата КАК ДатаДокумента,
| Документы.Контрагент КАК Контрагент,
| ДокументыТовары.Номенклатура КАК Номенклатура,
| ДокументыТовары.Количество КАК Количество,
| ДокументыТовары.Цена КАК Цена,
| ДокументыТовары.Сумма КАК Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документы
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК ДокументыТовары
| ПО Документы.Ссылка = ДокументыТовары.Ссылка
|ГДЕ
| Документы.Ссылка = &ДокументСсылка
|
|ИТОГИ ПО
| СсылкаДокумента,
| Номенклатура
|АВТОУПОРЯДОЧИВАНИЕ";
Запрос.УстановитьПараметр("ДокументСсылка", СсылкаНаРТиУ); // Ваша ссылка на документ
Построитель = Новый ПостроительЗапроса;
Построитель.Текст = Запрос.Текст;
В этом примере, СсылкаДокумента будет первым уровнем группировки, а Номенклатура — вторым. Это позволит создать дерево, где каждый документ будет родительским узлом, а под ним будут группироваться товары.
Выгружаем результат запроса в ДеревоЗначений.
После выполнения запроса с помощью ПостроителяЗапроса мы можем выгрузить его результат непосредственно в ДеревоЗначений, указав метод обхода ОбходРезультатаЗапроса.ПоГруппировкам или ОбходРезультатаЗапроса.ПоГруппировкамСИерархией.
ДеревоЗначений = Построитель.Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
Обратите внимание, что при таком подходе построитель запроса может автоматически добавить строку нулевого уровня с общими итогами. Если эта строка нам не нужна, ее, возможно, придется удалить программно после выгрузки дерева.
Если наши исходные данные находятся в файле Excel, мы можем загрузить их непосредственно в дерево значений, минуя промежуточную стадию создания таблицы значений. Этот подход особенно полезен для больших объемов данных или когда требуется более тонкий контроль над формированием иерархии непосредственно в процессе загрузки. Когда в качестве исходных данных выступают отчеты о продажах маркетплейсов в формате Excel, для их автоматической загрузки в 1С:Бухгалтерию 3.0 применяется обработка загрузки отчетов о продажах из Excel.
Читаем файл Excel.
Для чтения файла Excel мы обычно используем объекты COMОбъект("Excel.Application") (для толстого клиента Windows или сервера) или ТабличныйДокумент (для управляемого приложения, если файл открывается средствами 1С).
// Пример использования COM-объекта (только на Windows-сервере или толстом клиенте)
Попытка
ExcelПриложение = Новый COMОбъект("Excel.Application");
ExcelКнига = ExcelПриложение.Workbooks.Open("C:\Путь\К\Вашему\Файлу.xlsx");
ExcelЛист = ExcelКнига.Sheets(1); // Первый лист
// Далее читаем данные построчно
// ...
ExcelКнига.Close(Ложь);
ExcelПриложение.Quit();
Исключение
Сообщить("Ошибка при работе с Excel: " + ОписаниеОшибки());
КонецПопытки;
// Пример чтения с помощью ТабличныйДокумент (для управляемого приложения)
// ТабличныйДокумент можно получить из файла, загруженного через ПолеВыбораФайла
// или из временного хранилища.
ТабДок = Новый ТабличныйДокумент();
// ТабДок.Прочитать("C:\Путь\К\Вашему\Файлу.xlsx"); // Если есть прямой доступ к файлу
// Или, если это результат загрузки через форму:
// ТабДок.ЗагрузитьИзДвоичныхДанных(ДвоичныеДанныеФайла);
Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл // Предполагаем, что первая строка - заголовок
// Читаем данные из ячеек
// ЗначениеИзЯчейкиА = ТабДок.Область(НомерСтроки, 1).Текст;
// ...
КонецЦикла;
Программно заполняем ДеревоЗначений.
Во время чтения каждой строки или группы строк из Excel мы сразу же формируем соответствующую иерархию в ДеревеЗначений. Например, если в Excel есть строки, которые должны быть шапкой, и строки, которые должны быть табличной частью, мы можем анализировать данные Excel-файла и создавать родительские/дочерние строки в ДеревеЗначений по мере чтения.
ДЗ = Новый ДеревоЗначений;
ДЗ.Колонки.Добавить("ТипСтроки"); // Например, "Шапка" или "ТЧ"
ДЗ.Колонки.Добавить("Значение1");
ДЗ.Колонки.Добавить("Значение2");
// ... другие колонки
ТекущаяШапка = Неопределено;
Для НомерСтроки = 1 По МаксимальныйНомерСтрокиВExcel Цикл
// Читаем данные из текущей строки Excel
ДанныеСтрокиExcel = ПолучитьДанныеИзСтрокиExcel(НомерСтроки);
Если ДанныеСтрокиExcel.ТипСтроки = "Шапка" Тогда
// Создаем новую строку шапки
ТекущаяШапка = ДЗ.Строки.Добавить();
ТекущаяШапка.ТипСтроки = "Шапка";
ТекущаяШапка.Значение1 = ДанныеСтрокиExcel.НомерДокумента;
ТекущаяШапка.Значение2 = ДанныеСтрокиExcel.Дата;
// ...
ИначеЕсли ДанныеСтрокиExcel.ТипСтроки = "ТЧ" И ТекущаяШапка <> Неопределено Тогда
// Добавляем дочернюю строку к текущей шапке
СтрокаТЧ = ТекущаяШапка.Строки.Добавить();
СтрокаТЧ.ТипСтроки = "ТЧ";
СтрокаТЧ.Значение1 = ДанныеСтрокиExcel.Номенклатура;
СтрокаТЧ.Значение2 = ДанныеСтрокиExcel.Количество;
// ...
КонецЕсли;
КонецЦикла;
Этот метод предоставляет максимальный контроль над процессом преобразования, так как мы можем в любой момент применить любую логику для определения иерархии на основе содержимого Excel-файла.
При работе с ДеревомЗначений в 1С важно учитывать несколько ключевых аспектов, чтобы обеспечить корректную и эффективную работу:
Контекст выполнения: сервер или клиент.
ДеревоЗначений, как и ТаблицаЗначений, может быть создано и заполнено только в серверном контексте или на толстом клиенте. На тонком клиенте напрямую работать с ДеревомЗначений как с серверным объектом нельзя. Если мы хотим отобразить ДеревоЗначений в управляемой форме на тонком клиенте, оно должно быть реквизитом формы, который передается с сервера. Поэтому создание и заполнение ДереваЗначений рекомендуется выполнять в серверных процедурах или функциях.
Вспомогательные колонки для построения иерархии.
Для более сложной иерархии или для последующей обработки дерева может быть полезно использовать вспомогательные колонки, такие как КлючСтроки и КлючСвязи (или ИдентификаторРодителя). Эти колонки позволяют однозначно идентифицировать строки и их родительские элементы, что упрощает построение иерархии, особенно при наличии нескольких уровней или при необходимости восстановить иерархию после операций сортировки.
Готовые функции и модули.
В типовых решениях 1С (например, в Библиотеке электронных документов или БСП) часто встречаются готовые функции и методы для работы с коллекциями значений, включая загрузку таблиц в дерево значений. Например, в некоторых конфигурациях может присутствовать функция наподобие ЗагрузитьТаблицуВДерево() в общих модулях. Всегда полезно проверить, нет ли уже реализованных механизмов, которые можно использовать.
Вывод результата компоновки данных в ДеревоЗначений.
Система компоновки данных (СКД) также предоставляет возможность вывода результата в ДеревоЗначений. Для этого используется объект ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений. Важно помнить, что в этом случае в настройках СКД должны присутствовать только группировки и детальные записи. Использование таблиц, диаграмм, вложенных отчетов и других сложных макетов вывода в СКД не допускается при выгрузке в коллекции значений, так как они не могут быть адекватно представлены в древовидной структуре. Для упрощения программного вывода данных через компоновку можно использовать универсальную функцию для получения результата СКД в дерево значений.
Надеемся, что эти подробные инструкции помогут вам корректно и эффективно преобразовать ваши таблицы значений в иерархические деревья значений в 1С, будь то для отображения данных, дальнейшей обработки или формирования сложных отчетов.
Таблица значений в 1С — это универсальный табличный объект, предназначенный для хранения произвольных данных в памяти. Она представляет собой коллекцию строк, каждая из которых имеет набор колонок с определенными типами данных. Таблица значений часто используется для временного хранения данных, полученных из запросов, файлов или других источников, а также для формирования отчетов и обмена данными между различными частями программы. По своей структуре таблица значений похожа на плоскую таблицу в базе данных, где каждая строка является записью, а каждая колонка — полем.
Дерево значений в 1С — это иерархический объект, который представляет данные в виде древовидной структуры. В отличие от плоской таблицы значений, дерево значений состоит из узлов, которые могут иметь дочерние узлы, создавая уровни вложенности. Каждый узел (строка дерева) имеет набор колонок, аналогично таблице значений. Дерево значений идеально подходит для отображения и обработки данных, имеющих естественную иерархическую структуру, например, структуру справочников, документов с табличными частями, результаты группировок в отчетах.
Построитель запросов в 1С — это объект платформы, который позволяет программно формировать и выполнять запросы к базе данных. Он предоставляет удобный интерфейс для конструирования сложных запросов, настройки параметров, выполнения запросов и получения результатов. Построитель запросов особенно полезен, когда текст запроса необходимо динамически изменять в зависимости от условий, заданных пользователем или логикой программы. Он также интегрирован с механизмом системы компоновки данных и может использоваться для создания временных таблиц, отчетов и других операций с данными. Одной из ключевых особенностей построителя запросов является его способность работать с итогами и группировками, что делает его мощным инструментом для формирования иерархических данных, в том числе для выгрузки в дерево значений.