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