Почему не работает расшифровка при программном выводе отчета на СКД и как это исправить?

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

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

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

Анализ проблемы: почему ломается стандартный механизм

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

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

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

Быстрое решение: правильный вызов метода СкомпоноватьРезультат

Если вы компонуете отчет стандартным методом СкомпоноватьРезультат(), решение оказывается предельно простым. Нам достаточно передать второй параметр в этот метод — переменную, в которую система запишет сгенерированные данные расшифровки.

Рассмотрим пример правильного вызова в модуле формы отчета:


// В модуле формы обычного приложения
Процедура ДействиеСформировать(Кнопка)
    
    // Очищаем табличный документ результат
    ЭлементыФормы.Результат.Очистить();
    
    // Вызываем метод компоновки, передавая вторым параметром реквизит формы ДанныеРасшифровки
    СкомпоноватьРезультат(ЭлементыФормы.Результат, ДанныеРасшифровки);
    
КонецПроцедуры

Когда мы передаем реквизит ДанныеРасшифровки вторым параметром, платформа автоматически:

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

Пошаговый программный вывод СКД (полная схема)

В реальных задачах метод СкомпоноватьРезультат() часто не подходит, поскольку нам требуется тонкая настройка процесса вывода. Например, нужно установить внешние наборы данных, программно изменить структуру настроек или обработать вывод каждой строки индивидуально. В этом случае мы используем полную пошаговую схему вывода.

Разберем по шагам, как правильно инициализировать и передавать объект расшифровки на каждом этапе ручного вывода отчета СКД:

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

Посмотрим на пример кода, реализующего эту последовательность:


Процедура СформироватьОтчетВручную()
    
    ТабДок = ЭлементыФормы.Результат;
    ТабДок.Очистить();
    
    // 1. Инициализируем объект расшифровки
    ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
    
    // Получаем схему и настройки
    СхемаСКД = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    
    // 2. Компонуем макет, передавая объект расшифровки третьим параметром
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаСКД, Настройки, ДанныеРасшифровки);
    
    // Подготавливаем внешние наборы данных (например, нашу ТЗ)
    ВнешниеНаборы = Новый Структура;
    ВнешниеНаборы.Вставить("ТаблицаИсточника", ПолучитьТаблицуДанных());
    
    // 3. Инициализируем процессор компоновки с передачей данных расшифровки
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборы, ДанныеРасшифровки);
    
    // Выводим результат в табличный документ
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ТабДок);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    // 4. Обязательно связываем результат с формой для Обычного приложения
    ЭтаФорма.ДанныеРасшифровки = ДанныеРасшифровки;
    
КонецПроцедуры

Если пропустить хотя бы один из этих шагов (например, не передать переменную в КомпоновщикМакета.Выполнить() или забыть присвоить её свойству ЭтаФорма.ДанныеРасшифровки), расшифровка работать перестанет, и ячейки в итоговом табличном документе станут неактивными для клика.

Особенности расшифровки при использовании внешней Таблицы Значений (ТЗ)

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

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

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

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

Рассмотрим подробнее, как это сделать. Мы отключаем стандартное поведение платформы с помощью флага СтандартнаяОбработка = Ложь, самостоятельно получаем значение из расшифровки по её идентификатору и открываем нужную форму или программно переформируем отчет.


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

Различия механизмов расшифровки в Обычных и Управляемых формах

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

Основное отличие заключается в следующем:

Рассмотрим, как выглядит схема программного формирования отчета с расшифровкой на управляемых формах:


&НаСервере
Процедура СформироватьНаСервере()
    
    // Инициализируем серверный объект расшифровки
    АдресДанныхРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
    
    // Компонуем макет и инициализируем процессор компоновки (как в обычной схеме)
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), АдресДанныхРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , АдресДанныхРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    // Помещаем серверный объект во временное хранилище с привязкой к УИД формы
    АдресХранилища = ПоместитьВоВременноеХранилище(АдресДанныхРасшифровки, УникальныйИдентификатор);
    
    // Записываем строковый адрес в реквизит управляемой формы
    ДанныеРасшифровки = АдресХранилища;
    
КонецПроцедуры

При клике по ячейке на клиенте в процедуру РезультатОбработкаРасшифровки передается числовой идентификатор. Чтобы извлечь реальное значение поля на сервере, мы используем метод ПолучитьИзВременногоХранилища(ДанныеРасшифровки), после чего получаем нужный элемент по переданному идентификатору.

Резюме и рекомендации

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

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

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

← На главную