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