31 янв. 2017 г.

Произвольная иерархия в СКД

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

В СКД можно реализовать следующие варианты построения иерархии:
- к основному набору данных достраивается иерархическая структура;
- рекурсивное построение иерархии по одному набору данных.
В этом посте я хочу рассмотреть второй вариант на примере ресурсных спецификаций в демо-базе 1С:ERP 2.


Начнем с простого, получим иерархию детальных записей. Создадим в схеме компоновки набор данных с запросом:

ВЫБРАТЬ
 Т.Ссылка КАК СпецификацияРодитель,
 Т.ПроизводитсяВПроцессе,
 Т.ИсточникПолученияПолуфабриката КАК Спецификация,
 Т.Номенклатура,
 Т.Количество
ИЗ
 Справочник.РесурсныеСпецификации.МатериалыИУслуги КАК Т
ГДЕ
 Т.Ссылка В(&СписокСпецификаций)

Настроим связь набора:
- Спецификация >> СпецификацияРодитель;
- параметр связи СписокСпецификаций, как список параметров;
- условие связи ПроизводитсяВПроцессе
- начальное значение связи - параметр Спецификация, необходимо будет добавить на вкладке "Параметры".


Производим настройки схемы компоновки, добавляем группировку детальных записей.


Проверяем результат:


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

ВЫБРАТЬ
 Т.Ссылка КАК СпецификацияРодитель,
 Т.ПроизводитсяВПроцессе,
 Т.ИсточникПолученияПолуфабриката КАК Спецификация,
 Т.Номенклатура,
 Т.Количество
ИЗ
 Справочник.РесурсныеСпецификации.МатериалыИУслуги КАК Т
ГДЕ
 Т.Ссылка В(&СписокСпецификаций)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
 ЗНАЧЕНИЕ(Справочник.РесурсныеСпецификации.ПустаяСсылка),
 ИСТИНА,
 &Спецификация,
 &Спецификация,
 1

Так же переделаем настройки связей, в качестве начального значения связей теперь выступает ЗНАЧЕНИЕ(Справочник.РесурсныеСпецификации.ПустаяСсылка).


Уже лучше:


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

ВЫБРАТЬ
 Т.Ссылка КАК СпецификацияРодитель,
 Т.ПроизводитсяВПроцессе,
 Т.ИсточникПолученияПолуфабриката КАК Спецификация,
 Т.Номенклатура,
 Т.Количество * &КоличествоСпецификации КАК Количество,
 Т.Количество КАК КоличествоНормативное,
 &КоличествоСпецификации КАК КоличествоСпецификации
ИЗ
 Справочник.РесурсныеСпецификации.МатериалыИУслуги КАК Т
ГДЕ
 Т.Ссылка В (&СписокСпецификаций)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
 ЗНАЧЕНИЕ(Справочник.РесурсныеСпецификации.ПустаяСсылка),
 ИСТИНА,
 &Спецификация,
 &Спецификация,
 1,
 1,
 1
Настроим связи наборов, добавим еще одну строку:
- Количество >> КоличествоСпецификации;
- начальное значение 1.


Проверяем результат, получилось то, что надо и без единой строчки кода.


Теперь добавим вариант настроек для получения списка используемых материалов. Здесь особенность в том, что отбор используется для группировки "Номенклатура", а не для отчета в целом.



Ну и напоследок продемонстрирую отчет о входимости спецификации.

ВЫБРАТЬ
 Т.ИсточникПолученияПолуфабриката КАК СпецификацияПриемник,
 Т.Ссылка КАК Спецификация
ИЗ
 Справочник.РесурсныеСпецификации.МатериалыИУслуги КАК Т
ГДЕ
 Т.ПроизводитсяВПроцессе
 И Т.ИсточникПолученияПолуфабриката В(&СписокСпецификаций)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
 
 ЗНАЧЕНИЕ(Справочник.РесурсныеСпецификации.ПустаяСсылка),
 &Спецификация 



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


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




Скачать пример отчета



15 комментариев:

  1. Отличное решение, очень помогло построить дерево, только по плановым калькуляциям

    ОтветитьУдалить
  2. Совсем не понятно. Как рекурсивно строится иерархия? Где что и почему необходимо указывать в СКД.
    Пусть на входе таблица (источник не важен): Элемент, Родитель элемента.
    Как СКД для каждого элемента найдет всех подчиненных, а для каждого из подчиненных найдет их подчиненных.
    Пробовал по аналогии. Что бы посмотреть результат выгружал в дерево значений на форме - получаю плоский список.

    ОтветитьУдалить
  3. Этот комментарий был удален автором.

    ОтветитьУдалить
  4. Спасибо, автору. Получилось сделать отчет по вхождению материалов в изделия.

    ОтветитьУдалить
  5. Отличное решение, спасибо. Есть интересный вопрос. Если добавить поле "Вес" для каждой номенклатуры, кроме полуфабрикатов в специи указать вес. Как посчитать итоги по каждой специи в колонке "Вес". На момент вывода специи по полуфабрикату СКД не знает все вложенные специи, как их просуммировать? Если говорить о вашем примере как посчитать итоги по количеству номенклатуры по каждой специи?

    ОтветитьУдалить
  6. Спасибо автору, помог разобраться с этим магическим способом построения иерархии. Испытывал на примере "Иерархия подчиненности документов". В итоге сделал чуть по другому.
    Запрос в наборе данных такой:

    ВЫБРАТЬ
    ЗаказНаПроизводство.ДокументОснование,
    ЗаказНаПроизводство.Ссылка КАК ЗаказНаПроизводство
    ИЗ
    Документ.ЗаказНаПроизводство КАК ЗаказНаПроизводство
    ГДЕ
    ЗаказНаПроизводство.ДокументОснование В(&СписокСсылок)

    На закладке связи настройка: https://drive.google.com/file/d/1S9Wko7iJW7O-z7HFVqm6E95bG2qTtGak/view?usp=sharing

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

    ОтветитьУдалить
  7. А подскажите как сделать так, если это возможно, чтобы были итоги на уровнях (вложенных спецификациях), сейчас там число 1

    ОтветитьУдалить
    Ответы
    1. В последнем варианте есть вывод с подобными итогами. Не подходит?

      Удалить
    2. Не совсем Вас понял...
      Можете выложить пример кода, или настройки

      Удалить
  8. Спасибо, очень выручил ваш пример! Соединяю иерархический набор данных другим набором, при отборе поля пустой результат. Если отключить иерархическую связь отчет отрабатывает как надо, только вид отчета не подходит. Может Вы подскажете, что можно сделать?

    ОтветитьУдалить
  9. Хороший материал, все работает. Задача с деревом спецификаций и количеством - как раз то, что искала!
    З.Ы., момент на внимательность: здесь родитель - приемник связи, в других статьях есть примеры, когда родитель - источник. Так вот, с родителем-приемником у меня взлетело, а с родителем-источником - нет, выводит пустой отчет. Разница осталась непонятой:)

    ОтветитьУдалить
    Ответы
    1. Разница в том, что наборы соединяются левым соединением, Спецификация источника является Родителем для приемника, т.е. в этом случае ищем подчиненные элементы. Когда Родитель источник - получается ищем этого самого родителя, ссылку на спецификацию-родителя.

      Удалить
  10. Этот комментарий был удален автором.

    ОтветитьУдалить
  11. Спасибо огромное! То, что нужно!

    ОтветитьУдалить
  12. Можно ли как то передать 2 параметра в запрос-приемник, чтобы спустить серийный номер с верхнего уровня спецификации на подчиненные?

    ОтветитьУдалить