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

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

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

По умолчанию СКД рассчитывает ресурсы для иерархических записей путем агрегации (нахождения суммы, максимума или среднего значения) данных из дочерних элементов, полностью игнорируя реальные записи групп в базе данных. Проанализируем ситуацию: если у папки "Бытовая техника" в регистре установлена наценка 15%, а у входящих в нее товаров — 10% и 12%, СКД по умолчанию рассчитает ресурс для папки на основе дочерних элементов, проигнорировав ее собственную наценку.

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

Способ 1. Метод выборки групп в одном запросе с отбором «Без иерархии»

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

Рассмотрим подробнее реализацию этого подхода по шагам:

Шаг 1. Подготовка запроса. В основном запросе набора данных мы не должны накладывать жесткое условие ЭтоГруппа = Ложь. Нам необходимо выбрать все записи справочника Номенклатура (включая группы) и левым соединением подключить регистр сведений с наценками. Посмотрим на пример запроса:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Номенклатура,
    Номенклатура.ЭтоГруппа КАК ЭтоГруппа,
    ЕСТЬNULL(ПравилаЦенообразования.НаценкаПоУмолчанию, 0) КАК НаценкаПоУмолчанию
ПОМЕСТИТЬ ВтДанные
ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПравилаЦенообразования КАК ПравилаЦенообразования
        ПО Номенклатура.Ссылка = ПравилаЦенообразования.Номенклатура;

ВЫБРАТЬ
    ВтДанные.Номенклатура КАК Номенклатура,
    ВтДанные.ЭтоГруппа КАК ЭтоГруппа,
    ВтДанные.НаценкаПоУмолчанию КАК НаценкаПоУмолчанию
ИЗ
    ВтДанные КАК ВтДанные

Шаг 2. Настройка ресурсов СКД. Поскольку строки папок физически присутствуют в результате запроса, у них есть свое собственное значение наценки из регистра. Чтобы СКД не складывала наценки подчиненных элементов при выводе папки, настроим выражение ресурса. Перейдем на вкладку «Ресурсы» и добавим поле НаценкаПоУмолчанию.

Для расчета по группировке Номенклатура (детальные записи элементов) укажем выражение:

Максимум(НаценкаПоУмолчанию)

Для расчета по группировке Номенклатура Иерархия (родительские узлы дерева) укажем специальное выражение:

Максимум(Выбор Когда ЭтоГруппа Тогда НаценкаПоУмолчанию Иначе NULL Конец)

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

Шаг 3. Исключение дублирования папок. Если запустить отчет сейчас, папки продублируются: они выведутся как узлы группировки и как детальные записи внутри этих узлов. Чтобы избавиться от этого, настроим отбор в СКД. Перейдем в настройки структуры отчета, выберем группировку Номенклатура и на вкладке «Отбор» добавим условие: ЭтоГруппа Равно Ложь. В колонке «Применение» обязательно выберем значение Без иерархии. Это укажет СКД применить отбор только к конечным детальным записям, сохранив структуру дерева иерархии нетронутой.

Способ 2. Настройка связей наборов данных (Стандартный подход платформы)

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

Разберем по шагам, как настроить эту связь:

Шаг 1. Создание наборов данных. В схеме компоновки создадим два набора данных типа «Запрос»:

  1. НаборДанных1 (Основной) — выбирает только элементы номенклатуры:
    
    ВЫБРАТЬ
        Номенклатура.Ссылка КАК Номенклатура,
        Номенклатура.Родитель КАК Родитель
    ИЗ
        Справочник.Номенклатура КАК Номенклатура
    ГДЕ
        Номенклатура.ЭтоГруппа = ЛОЖЬ
    
  2. НаборДанных2 (Иерархия) — запрашивает данные регистра для конкретного родительского узла:
    
    ВЫБРАТЬ
        Номенклатура.Ссылка КАК Номенклатура,
        Номенклатура.Родитель КАК Родитель,
        ЕСТЬNULL(ПравилаЦенообразования.НаценкаПоУмолчанию, 0) КАК НаценкаГруппы
    ИЗ
        Справочник.Номенклатура КАК Номенклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПравилаЦенообразования КАК ПравилаЦенообразования
            ПО Номенклатура.Ссылка = ПравилаЦенообразования.Номенклатура
    ГДЕ
        Номенклатура.Ссылка В (&НоменклатураСсылка)
    

Шаг 2. Настройка связей наборов. Перейдем на вкладку «Связи наборов данных». Добавим новую строку:

При построении иерархической группировки СКД самостоятельно передаст ссылку на текущую обрабатываемую группу в параметр &НоменклатураСсылка второго набора данных и получит точную наценку для этой группы напрямую из регистра сведений. Ресурс НаценкаГруппы в этом случае рассчитывается стандартной функцией Максимум(НаценкаГруппы) для всех уровней группировки.

Способ 3. Получение унаследованных наценок через функцию ВычислитьВыражение

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

Посмотрим на пример выражения, которое можно указать в ресурсах для поля наценки:

ВычислитьВыражение("НаценкаПоУмолчанию", , "Иерархия", "Первая", "Текущая")

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

Способ 4. Программный расчет родителей в модуле отчета (Альтернативный вариант)

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

В модуле отчета в обработчике ПриКомпоновкеРезультата мы можем использовать следующий алгоритм для заполнения списка значений родительских групп:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    Настройки = КомпоновщикНастроек.Настройки;
    
    // Получаем выбранную пользователем группу номенклатуры
    ГруппаНоменклатуры = ПолучитьПользовательскийПараметр("ГруппаНоменклатуры", КомпоновщикНастроек).Значение;
    
    СписокРодителей = Новый СписокЗначений;
    СписокРодителей.Добавить(ГруппаНоменклатуры);
    
    ТекущийЭлемент = ГруппаНоменклатуры;
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Родитель КАК Родитель,
        |   Номенклатура.Родитель.Родитель КАК Родитель2,
        |   Номенклатура.Родитель.Родитель.Родитель КАК Родитель3
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |   Номенклатура.Ссылка = &ТекущийЭлемент";
        
    Пока Истина Цикл
        Запрос.УстановитьПараметр("ТекущийЭлемент", ТекущийЭлемент);
        Результат = Запрос.Выполнить();
        Если Результат.Пустой() Тогда
            Прервать;
        КонецЕсли;
        
        Выборка = Результат.Выбрать();
        Выборка.Следующий();
        
        Для НомерКолонки = 0 По Результат.Колонки.Количество() - 1 Цикл
            ТекущийЭлемент = Выборка[НомерКолонки];
            Если ТекущийЭлемент = Справочники.Номенклатура.ПустаяСсылка() Тогда
                Прервать;
            Иначе
                СписокРодителей.Добавить(ТекущийЭлемент);
            КонецЕсли;
        КонецЦикла;
        
        Если ТекущийЭлемент = Справочники.Номенклатура.ПустаяСсылка() Тогда
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    // Передаем заполненный список в параметры СКД
    ПараметрСписок = Настройки.ПараметрыДанных.Элементы.Найти("СписокРодителей");
    Если ПараметрСписок <> Неопределено Тогда
        ПараметрСписок.Значение = СписокРодителей;
        ПараметрСписок.Использование = Истина;
    КонецЕсли;
КонецПроцедуры

Затем в основном запросе СКД накладывается условие вхождения номенклатуры либо в полученный список родителей, либо в иерархию выбранной группы:


ГДЕ (Номенклатура.Ссылка В (&СписокРодителей) ИЛИ Номенклатура.Ссылка В ИЕРАРХИИ (&ГруппаНоменклатуры))

Хотя этот метод полностью решает задачу автора, он обладает существенным недостатком — низкой производительностью на больших объемах данных из-за частых обращений к базе данных в цикле. Мы рекомендуем использовать Способ 1 или Способ 2 как наиболее оптимальные и соответствующие стандартам разработки фирмы 1С.

Подводя итоги, отметим, что выбор конкретного метода зависит от структуры ваших данных и требований к производительности. Использование механизма «Без иерархии» (Способ 1) идеально подойдет для простых отчетов, тогда как связь наборов данных (Способ 2) незаменима при сложной архитектуре метаданных. Применяйте правильные проектные решения и создавайте быстрые, надежные отчеты на платформе 1С!

← На главную