Как правильно настроить программную расшифровку в отчете СКД на управляемых формах

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

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

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

Причины проблем с расшифровкой при ручном выводе СКД

Проанализируем типичные ошибки, возникающие при реализации расшифровки:

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

Шаг 1. Программное формирование отчета и сохранение данных расшифровки

Рассмотрим правильный алгоритм формирования отчета на сервере. Формирование можно выполнять как в модуле объекта (в событии ПриКомпоновкеРезультата), так и в модуле формы. Главное условие — инициализировать компоновщик макета с объектом расшифровки и сохранить результат во временное хранилище с уникальным идентификатором формы.

Посмотрим на пример процедуры формирования отчета в модуле управляемой формы:


&НаСервере
Процедура СформироватьОтчетНаСервере()
    
    // Получаем схему компоновки и настройки
    СхемаКомпоновкиДанных = Отчеты.АР_ОтчетПоРасходам.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = Отчет.КомпоновщикНастроек.ПолучитьНастройки();
    
    // Создаем объект для сбора данных расшифровки
    ДанныеРасшифровкиОбъект = Новый ДанныеРасшифровкиКомпоновкиДанных;
    
    // Макетирование компоновки
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровкиОбъект);
    
    // Инициализация процессора компоновки
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровкиОбъект);
    
    // Очищаем и настраиваем табличный документ формы (реквизит Результат)
    Элементы.Результат.Очистить();
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    // Помещаем данные расшифровки во временное хранилище с ключом формы
    АдресРасшифровки = ПоместитьВоВременноеХранилище(ДанныеРасшифровкиОбъект, УникальныйИдентификатор);
    
    // Связываем поле табличного документа с адресом расшифровки
    Элементы.Результат.ДанныеРасшифровки = АдресРасшифровки;
    
    // Сохраняем адрес в строковый реквизит формы для дальнейшей обработки
    ДанныеРасшифровки = АдресРасшифровки;
    
КонецПроцедуры

Обратите внимание: на форме отчета реквизит ДанныеРасшифровки должен иметь тип Строка. В него записывается строковый URL временного хранилища (например, e1cib/tempstorage/...).

Шаг 2. Перехват события ОбработкаРасшифровки

Чтобы выполнить собственные действия при клике на ячейку отчета, назначим обработчик события ОбработкаРасшифровки для элемента формы Результат.

Посмотрим на клиентский обработчик события:


&НаКлиенте
Процедура РезультатОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
    
    // Отключаем стандартное всплывающее меню СКД
    СтандартнаяОбработка = Ложь;
    
    // Передаем числовой идентификатор ячейки на сервер
    ОбработатьРезультатНаСервере(Расшифровка);
    
КонецПроцедуры

Шаг 3. Извлечение полей строки и колонки (кросс-таблицы)

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

Чтобы узнать, к какой строке (по вертикали) и к какой колонке (по горизонтали) относится данная ячейка, необходимо вызвать метод ПолучитьРодителей(). Метод возвращает массив родительских группировок типа ЭлементРасшифровкиКомпоновкиДанныхГруппировка:

  1. Один из родителей представляет группировку строк.
  2. Второй родитель представляет группировку колонок.

Разберем процедуру анализа расшифровки на сервере:


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

Рекурсивный сбор всех уровней группировок

Если в отчете используется сложная многоуровневая структура (например, Организация → Подразделение → Номенклатура в строках и Год → Месяц в колонках), прямого обращения к первому уровню родителей недостаточно. В таких ситуациях применим рекурсивный обход всех вышестоящих родителей для полного сбора контекста кликнутой ячейки.

Посмотрим на универсальную функцию обхода дерева расшифровки:


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

Такой подход гарантирует, что независимо от сложности настроек отчета будут корректно определены все значения измерений строк и колонок, на пересечении которых находилась выбранная сумма.

← На главную