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

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

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

Понимание проблемы: Расшифровка и динамические группировки

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

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

Ключевой объект: ДанныеРасшифровки

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

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

Структура объекта ДанныеРасшифровки

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

  1. ЭлементРасшифровкиКомпоновкиДанныхПоля

    Этот тип элемента содержит список значений полей, которые присутствуют в расшифровываемой ячейке. Для каждого значения доступны:

    • Путь к данным поля (например, "Номенклатура.ОсновнойПоставщик").
    • Само значение поля (например, конкретный элемент справочника "Номенклатура").
    • Признак того, что значение было получено для иерархической записи, если это применимо.

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

  2. ЭлементРасшифровкиКомпоновкиДанныхГруппировка

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

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

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

Пошаговый алгоритм получения имени группировки

Рассмотрим пошаговый алгоритм, как мы можем получить имя группировки при обработке расшифровки.

  1. Перехват события расшифровки

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

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

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

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

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

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

    В цикле перебора родительских элементов нам необходимо проверять их тип. Если тип элемента соответствует ЭлементРасшифровкиКомпоновкиДанныхГруппировка, то мы нашли искомую группировку. Из этого элемента мы можем извлечь его имя, которое и будет искомым именем группировки. Также, если необходимо, мы можем получить значение поля, по которому группировка была сформирована.

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

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

Пример использования в типовой конфигурации с БСП

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

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


// Пример упрощенной структуры переопределяемой процедуры
// Общий модуль ОтчетыКлиентПереопределяемый (клиент)

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

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

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

    ЭлементРасшифровки = ДанныеРасшифровки.Элементы[ИдентификаторРасшифровки];

    Если ЭлементРасшифровки = Неопределено Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    // Включаем текущий элемент в поиск, чтобы учесть расшифровку по самому полю
    МассивИдентификаторовДляПоиска = Новый Массив;
    МассивИдентификаторовДляПоиска.Добавить(ИдентификаторРасшифровки);
    
    Для Каждого РодительскийИД Из ЭлементРасшифровки.ПолучитьРодителей() Цикл
        МассивИдентификаторовДляПоиска.Добавить(РодительскийИД);
    КонецЦикла;

    // Обходим элементы в обратном порядке, чтобы найти ближайшую к расшифровке группировку
    Для Индекс = МассивИдентификаторовДляПоиска.Количество() - 1 По 0 Шаг -1 Цикл
        ТекущийИдентификатор = МассивИдентификаторовДляПоиска[Индекс];
        ТекущийЭлемент = ДанныеРасшифровки.Элементы[ТекущийИдентификатор];
        
        Если ТекущийЭлемент = Неопределено Тогда
            Продолжить;
        КонецЕсли;

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

            Возврат Новый Структура("ИмяГруппировки, ЗначениеГруппировки", ИмяГруппировки, ЗначениеГруппировки);
        КонецЕсли;
    КонецЦикла;
    
    Возврат Неопределено; // Группировка не найдена
КонецФункции

Заключение

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

← На главную