Как получить значения из строк и колонок при расшифровке в таблице СКД

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с расшифровкой в Системе компоновки данных (СКД) часто преподносит сюрпризы, особенно когда отчет построен в виде таблицы. В обычном списке иерархия объектов расшифровки линейна: у ячейки есть один родитель (группировка), у той — свой родитель и так далее до корня. Однако в таблице, где данные выводятся на пересечении строк и колонок, архитектура меняется. Ячейка с ресурсом одновременно принадлежит и ветке строк, и ветке колонок. Разберем подробно, как программно извлечь данные из обеих независимых группировок.

Анализ проблемы: почему стандартный подход не видит одну из осей

Рассмотрим ситуацию: у нас есть отчет, где в строках выбрана Номенклатура, а в колонках — Период. При нажатии на сумму в ячейке мы ожидаем получить и конкретный товар, и конкретный месяц. Проблема заключается в том, что многие разработчики по привычке обращаются к первому элементу массива родителей или пытаются найти данные в текущих полях расшифровки. Но в таблице СКД метод ПолучитьРодителей() возвращает массив, содержащий ссылки на обе ветки иерархии. Если мы просто возьмем Родитель[0], мы получим либо номенклатуру, либо период, но не всё сразу.

Чтобы решить эту задачу, нам необходимо реализовать алгоритм, который будет «обходить» всех родителей рекурсивно, собирая значения всех доступных полей группировок.

Шаг 1. Перехват расшифровки на клиенте

Прежде всего, нам нужно отключить стандартную обработку расшифровки в форме отчета, чтобы программно управлять процессом. Для этого используется событие табличного документа ОбработкаРасшифровки. Проанализируем пример кода для клиентской части:


&НаКлиенте
Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка, ДополнительныеПараметры)
    
    СтандартнаяОбработка = Ложь; // Отключаем стандартное окно 1С
    
    // Подготавливаем структуру для поиска нужных нам полей
    СтруктураПолей = Новый Структура;
    СтруктураПолей.Вставить("Номенклатура", Неопределено);
    СтруктураПолей.Вставить("Период", Неопределено);
    
    // Вызываем серверную функцию для анализа дерева расшифровки
    ПолучитьДанныеРасшифровкиНаСервере(Расшифровка, СтруктураПолей);
    
    // Теперь в СтруктураПолей лежат значения из строк и колонок
    Если ЗначениеЗаполнено(СтруктураПолей.Номенклатура) Тогда
        // Здесь можно открыть другой отчет или форму, передав параметры
        ПараметрыВыбора = Новый Структура("Отбор", СтруктураПолей);
        ОткрытьФорму("Отчет.МойДетальныйОтчет.Форма", ПараметрыВыбора);
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Рекурсивный поиск значений по дереву родителей

На сервере нам необходимо получить объект ДанныеРасшифровкиКомпоновкиДанных из временного хранилища (куда он попадает при формировании отчета) и извлечь значения. Основная сложность — пройти по всем «родителям» ячейки. Посмотрим на эффективную рекурсивную функцию:


&НаСервере
Процедура ПолучитьСтруктуруВозврата(ЭлементРасшифровки, СтруктураПолей)
    
    // Получаем массив всех родителей (для таблицы их будет минимум два)
    МассивРодителей = ЭлементРасшифровки.ПолучитьРодителей();
    
    Для Каждого Родитель Из МассивРодителей Цикл
        
        // Проверяем, является ли родитель группировкой
        Если ТипЗнч(Родитель) = Тип("ЭлементРасшифровкиКомпоновкиДанныхГруппировка") Тогда
            
            // Получаем поля этой группировки
            ПоляГруппировки = Родитель.ПолучитьПоля();
            Для Каждого Поле Из ПоляГруппировки Цикл
                
                // Если имя поля совпадает с искомым в нашей структуре, заполняем значение
                Если СтруктураПолей.Свойство(Поле.Поле) Тогда
                    Если СтруктураПолей[Поле.Поле] = Неопределено Тогда
                        СтруктураПолей[Поле.Поле] = Поле.Значение;
                    КонецЕсли;
                КонецЕсли;
                
            КонецЦикла;
            
            // Рекурсивно поднимаемся выше по дереву к корню
            ПолучитьСтруктуруВозврата(Родитель, СтруктураПолей);
            
        ИначеЕсли ТипЗнч(Родитель) = Тип("ЭлементРасшифровкиКомпоновкиДанныхПоля") Тогда
            // Обработка случая, если это просто поля
            ПолучитьСтруктуруВозврата(Родитель, СтруктураПолей);
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Шаг 3. Вспомогательная функция получения данных

Для корректной работы серверной части нам нужно извлечь сами данные расшифровки, используя адрес временного хранилища, который СКД автоматически создает при выводе отчета в табличный документ.


&НаСервере
Процедура ПолучитьДанныеРасшифровкиНаСервере(ИдентификаторРасшифровки, СтруктураПолей)
    
    // АдресДанныхРасшифровки — это реквизит формы, куда СКД кладет данные
    Данные = ПолучитьИзВременногоХранилища(ДанресАдресДанныхРасшифровки);
    
    // Находим элемент, по которому кликнул пользователь
    ТекущийЭлемент = Данные.Элементы[ИдентификаторРасшифровки];
    
    // Если пользователь кликнул на саму ячейку ресурса, сначала проверим её поля
    Если ТипЗнч(ТекущийЭлемент) = Тип("ЭлементРасшифровкиКомпоновкиДанныхПоля") Тогда
        Для Каждого Поле Из ТекущийЭлемент.ПолучитьПоля() Цикл
            Если СтруктураПолей.Свойство(Поле.Поле) Тогда
                СтруктураПолей[Поле.Поле] = Поле.Значение;
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    
    // Запускаем рекурсивный поиск по родителям (строкам и колонкам)
    ПолучитьСтруктуруВозврата(ТекущийЭлемент, СтруктураПолей);
    
КонецПроцедуры

Важные нюансы и рекомендации

Проанализируем несколько критических моментов, которые могут возникнуть при использовании данного подхода:

  1. Инициализация расшифровки: Если вы формируете отчет программно, убедитесь, что при вызове метода ПроцессорКомпоновкиДанных.Инициализировать() вы передали вторым параметром объект данных расшифровки. В противном случае переменная Расшифровка в событии будет содержать просто число, которое невозможно превратить в данные.
  2. Работа с итогами: Если пользователь нажимает на ячейку в колонке «Итого», одна из ветвей (например, Период) будет отсутствовать в родителях. Всегда проверяйте значения в структуре на Неопределено перед использованием.
  3. Типы данных элементов: Обратите внимание, что мы проверяем ТипЗнч(Родитель). Группировки в таблицах представлены объектами ЭлементРасшифровкиКомпоновкиДанныхГруппировка. Именно у них через метод ПолучитьПоля() можно достать значение ссылки на объект (Номенклатура, Склад и т.д.).
  4. Производительность: Рекурсивный обход в 1С работает достаточно быстро, но для очень сложных отчетов с десятками уровней иерархии стоит ограничивать поиск только нужными полями, как это сделано в примере через СтруктураПолей.Свойство().

Таким образом, мы выяснили причину «невидимости» полей: в таблице СКД связь между строкой и колонкой в расшифровке реализована через ветвление массива родителей. Используя предложенный алгоритм, вы сможете корректно обрабатывать клики в любых сложных табличных отчетах, обеспечивая пользователям удобную навигацию и детализацию данных.

← На главную