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

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

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

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

Общая схема решения задачи

Для реализации полноценной расшифровки нам понадобится выполнить три последовательных шага:

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

Рассмотрим каждый из этих шагов подробно с примерами готового кода.

Шаг 1: Перехват события расшифровки на клиенте

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

В модуле управляемой формы отчета пропишем следующий код:


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

Шаг 2: Программный обход дерева расшифровки на сервере

Это самый важный этап работы. Когда пользователь кликает по ячейке (особенно по ресурсу или группировке), нам доступен только идентификатор расшифровки — число. Нам нужно восстановить весь контекст строки, то есть подняться по дереву группировок вверх до самого корня и собрать значения всех измерений нашего регистра.

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


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

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

Шаг 3: Открытие формы записи регистра

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

Вариант А: Использование ключа записи для редактирования существующей записи

Если мы уверены, что запись в базе данных уже существует, мы можем использовать специальный объект РегистрСведенийКлючЗаписи. Мы можем сконструировать его прямо на клиенте без лишних обращений к серверной базе данных:


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

Вариант Б: Универсальный подход с поддержкой создания новых записей

Бывают ситуации, когда в отчете выводится сетка (например, матрица "Товары / Склады"), где на пересечении строк и колонок данных еще нет. При клике на пустую ячейку пользователь ожидает открытия формы создания новой записи, где измерения уже будут предзаполнены значениями из строк и колонок отчета.

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

Проанализируем универсальный клиентский метод, который задействует механизмы Библиотеки стандартных подсистем (БСП), если она интегрирована в вашу конфигурацию:


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

Данный метод БСП самостоятельно проверит на сервере существование записи по переданному отбору. Если запись существует, будет открыта форма редактирования существующей записи. Если запись не найдена, откроется форма создания новой записи с уже заполненными измерениями, что исключает ручной ввод со стороны пользователя.

Альтернативный вариант: Использование макетов СКД

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

Вы можете настроить **собственный макет ячейки** в схеме компоновки данных:

  1. Откройте схему компоновки данных (СКД) вашего отчета и перейдите на вкладку Макеты.
  2. Добавьте новый макет поля или макет группировки.
  3. В свойствах ячейки макета найдите свойство Параметр расшифровки и укажите для него произвольное имя (например, ПараметрЗаписиРегистра).
  4. В выражении этого параметра соберите структуру или строку со всеми необходимыми измерениями прямо средствами языка выражений СКД.

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

← На главную