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