Табличные части документов в платформе 1С:Предприятие представляют собой плоские коллекции строк. Платформа не поддерживает хранение иерархических структур непосредственно внутри табличной части на уровне базы данных. Однако при работе с документами (например, при бюджетировании, расчете затрат или калькуляции спецификаций) часто возникает необходимость отобразить данные сгруппированными по уровням с возможностью сворачивания и разворачивания узлов, а также автоматическим подсчетом итогов по группам.
Разберем подробный алгоритм решения этой задачи: как выгрузить данные табличной части в реквизит формы типа ДеревоЗначений, сформировать иерархию с подсчетом итоговых сумм с помощью запроса и организовать обратную запись отредактированных данных в документ.
Для реализации иерархического отображения на управляемой форме создадим реквизит формы с типом ДеревоЗначений (например, ДЗИтоговыеЗатраты). Табличная часть документа (например, ТЧИтоговыеЗатраты) будет хранить только конечные детальные строки (листья дерева).
Процесс работы строится по следующей схеме:
ИТОГИ СУММА(...) ПО ... ИЕРАРХИЯ.ДЗИтоговыеЗатраты.Объект.ТЧИтоговыеЗатраты.Рассмотрим серверную процедуру ПриСозданииНаСервере. В ней мы выполняем запрос к табличной части текущего документа, группируем суммы по видам затрат и заполняем дерево значений формы.
Для конвертации реквизита формы в объект `ДеревоЗначений` и обратно применяются методы РеквизитФормыВЗначение() и ЗначениеВРеквизитФормы().
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЧИтоговыеЗатраты.ВидыЗатрат КАК ВидыЗатрат,
| ТЧИтоговыеЗатраты.Сумма КАК Сумма
|ИЗ
| Документ.Проекты.ТЧИтоговыеЗатраты КАК ТЧИтоговыеЗатраты
|ГДЕ
| ТЧИтоговыеЗатраты.Ссылка = &ТекДок
|ИТОГИ
| СУММА(Сумма)
|ПО
| ВидыЗатрат ИЕРАРХИЯ";
Запрос.УстановитьПараметр("ТекДок", Объект.Ссылка);
Выборка = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
// Преобразуем реквизит формы в объект ДеревоЗначений для программного заполнения
ДЗИтоговыеЗатратыРФВЗ = РеквизитФормыВЗначение("ДЗИтоговыеЗатраты");
ДЗИтоговыеЗатратыРФВЗ.Строки.Очистить();
// Обходим верхний уровень группировки (родительские узлы)
Пока Выборка.Следующий() Цикл
РодительскаяСтрока = ДЗИтоговыеЗатратыРФВЗ.Строки.Добавить();
РодительскаяСтрока.ВидыЗатрат = Выборка.ВидыЗатрат;
РодительскаяСтрока.Сумма = Выборка.Сумма;
// Получаем детальные строки для текущей группы
ВыборкаНижнийУровень = Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
Пока ВыборкаНижнийУровень.Следующий() Цикл
ПодчиненнаяСтрока = РодительскаяСтрока.Строки.Добавить();
ПодчиненнаяСтрока.ВидыЗатрат = ВыборкаНижнийУровень.ВидыЗатрат;
ПодчиненнаяСтрока.Сумма = ВыборкаНижнийУровень.Сумма;
КонецЦикла;
КонецЦикла;
// Помещаем сформированное дерево обратно в реквизит формы
ЗначениеВРеквизитФормы(ДЗИтоговыеЗатратыРФВЗ, "ДЗИтоговыеЗатраты");
КонецПроцедуры
На стороне клиента в обработчике ПриОткрытии зададим начальное отображение дерева на форме, чтобы все узлы автоматически разворачивались при открытии:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Элементы.ДЗИтоговыеЗатраты.НачальноеОтображениеДерева = НачальноеОтображениеДерева.РаскрыватьВсеУровни;
КонецПроцедуры
Проанализируем процесс сохранения данных. Позиции верхнего уровня в дереве являются виртуальными (суммовыми итогами). В табличную часть документа должны попадать только конечные детальные строки. При изменении данных в дереве на форме запускаем процедуру перезаполнения табличной части объекта.
&НаСервере
Процедура ДЗИтоговыеЗатратыПриИзмененииНаСервере()
ДЗИтоговыеЗатратыРФВЗ = РеквизитФормыВЗначение("ДЗИтоговыеЗатраты");
// Очищаем табличную часть документа перед перезаполнением
Объект.ТЧИтоговыеЗатраты.Очистить();
// Обходим верхний уровень (группы)
Для Каждого ГруппаИзДерева Из ДЗИтоговыеЗатратыРФВЗ.Строки Цикл
// Обходим только дочерние детальные строки группы
Для Каждого СтрокаЭлемента Из ГруппаИзДерева.Строки Цикл
НоваяСтрокаТЧ = Объект.ТЧИтоговыеЗатраты.Добавить();
НоваяСтрокаТЧ.ВидыЗатрат = СтрокаЭлемента.ВидыЗатрат;
НоваяСтрокаТЧ.Сумма = СтрокаЭлемента.Сумма;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ДЗИтоговыеЗатратыПриИзменении(Элемент)
ДЗИтоговыеЗатратыПриИзмененииНаСервере();
КонецПроцедуры
Для более наглядного визуального разделения групп и детальных строк на управляемой форме рекомендуется использовать Условное оформление. Чтобы выделить жирным шрифтом или цветом только родительские узлы (верхний уровень), выполним следующие настройки:
ДЗИтоговыеЗатраты дополнительную колонку ЭтоГруппа с типом Булево.РодительскаяСтрока.ЭтоГруппа = Истина, а для подчиненных — ПодчиненнаяСтрока.ЭтоГруппа = Ложь.УсловноеОформление и создаем новый элемент оформления:
ДЗИтоговыеЗатраты.ЭтоГруппа Равно Истина.ДЗИтоговыеЗатраты.Этот подход позволяет гибко настраивать визуальное отображение группировок без использования устаревших событий вывода строк и с полным соблюдением стандартов разработки под управляемое приложение 1С.