Как построить произвольную иерархию спецификаций в СКД без некорректного суммирования ресурсов?

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

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

Разберем природу этой проблемы и рассмотрим несколько способов ее решения.

В чем причина некорректного суммирования в СКД?

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

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

Способ 1. Использование суррогатных уникальных ключей узла

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

  1. На этапе формирования таблицы значений в коде (или во внешнем наборе данных) добавим колонки ИД_Узла и ИД_Родителя:
    
    ТЗДанные = Новый ТаблицаЗначений;
    ТЗДанные.Колонки.Добавить("ИД_Узла", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(36)));
    ТЗДанные.Колонки.Добавить("ИД_Родителя", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(36)));
    ТЗДанные.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
    ТЗДанные.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
    
  2. При заполнении таблицы для каждой новой строки генерируем уникальный ключ через Строка(Новый УникальныйИдентификатор) или строковый номер узла, а в ИД_Родителя записываем идентификатор родительской ветки. Для корневого элемента значение ИД_Родителя остается пустым.
  3. В СКД на вкладке «Связи наборов данных» настраиваем связь набора данных с самим собой:
    1. Источник связи: НаборДанных1.
    2. Приемник связи: НаборДанных1.
    3. Выражение источника: ИД_Узла.
    4. Выражение приемника: ИД_Родителя.
  4. В структуре отчета добавляем группировку с иерархией по полю ИД_Узла.
  5. Чтобы в отчете отображалось человекочитаемое название номенклатуры вместо GUID, на вкладке «Наборы данных» для поля ИД_Узла задаем свойство Выражение представления: Номенклатура.

Способ 2. Формирование плоской таблицы с уровнями переделов

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

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

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

Способ 3. Связь наборов данных по спецификациям

Если иерархия строится запросом непосредственно внутри схемы компоновки, связь следует настраивать не по номенклатуре, а по спецификациям узлов.

  1. Создаем набор данных — запрос, выбирающий исходные комплектующие:
    
    ВЫБРАТЬ
        Спецификация.Ссылка КАК СпецификацияРодитель,
        Спецификация.Номенклатура КАК Полуфабрикат,
        ИсходныеКомплектующие.Номенклатура КАК Материал,
        ИсходныеКомплектующие.Количество КАК Количество
    ИЗ
        Справочник.СпецификацииНоменклатуры.ИсходныеКомплектующие КАК ИсходныеКомплектующие
    ГДЕ
        Спецификация.Ссылка В (&СписокРодителей)
    
  2. На вкладке «Связи наборов данных» создаем иерархическую связь с передачей текущей спецификации в параметр &СписокРодителей для рекурсивного разузлования на каждом последующем шаге.

Настройка расчета ресурсов в иерархических отчетах

При использовании рекурсивных иерархий обратим внимание на вкладку «Ресурсы» схемы компоновки данных. По умолчанию СКД пытается сложить значения всех родительских и дочерних строк. Чтобы исключить некорректный двойной счет:

  1. В колонке «Рассчитывать по...» снимем флажки с тех промежуточных группировок, где количество полуфабриката не должно складываться с количеством входящих в него материалов.
  2. При необходимости расчета специфических итогов применим функцию ВычислитьВыражение() с указанием контекста "Группировка" или "Иерархия".
← На главную