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