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