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

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

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

Почему старый код не работает в управляемых формах

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

Шаг 1. Обработка события на клиенте

Для начала проанализируем событие РезультатОбработкаРасшифровки. Оно возникает в модуле формы отчета, когда пользователь дважды кликает по ячейке или выбирает пункт меню расшифровки. Нам нужно установить СтандартнаяОбработка = Ложь, чтобы прервать стандартный механизм 1С и запустить свой собственный.

Рассмотрим пример кода на стороне клиента:


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

Шаг 2. Получение данных на сервере

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


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

Шаг 3. Как получить данные всей строки (других колонок)

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

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


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

Шаг 4. Открытие типового бухгалтерского отчета

Теперь, когда у нас есть структура со всеми данными строки (Контрагент, Организация, Период), мы можем вызвать стандартный отчет. В типовых конфигурациях (например, БП 3.0) это делается через метод ОткрытьФорму с передачей специальных параметров.

Рассмотрим пример вызова Оборотно-сальдовой ведомости по счету:


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

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

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

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

← На главную