&НаСервере
// + //infostart.ru/profile/504528/ 20190328
// Параметры:
// фМассивТаблицаНоменклатуры - Массив, заполненный значениями справочника "Номенклатура", либо Таблица значений с колонкой "Номенклатура"
// фКоличествоРодителей - целое Число, определяет какое количество родителей "верхнего" уровня необходимо получить
// УровеньРекурсии - технический параметр, отражающий текущий уровень рекурсии - передавать не нужно!
//
// Функция возвращает таблицу значений с колонками "Номенклатура", "НоменалутраРодитель1", ... , "НоменклатураРодительN", где N - значение параметра "фКоличествоРодителей"
// - //infostart.ru/profile/504528/ 20190328
Функция ПолучитьТаблицуРодителейНоменклатурыРекурсией(фМассивТаблицаНоменклатуры = Неопределено, фКоличествоРодителей = 2, УровеньРекурсии = 0) Экспорт
Если фМассивТаблицаНоменклатуры = Неопределено Тогда
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
| сНоменклатура.Ссылка КАК Номенклатура
|ИЗ
| Справочник.Номенклатура КАК сНоменклатура
|ГДЕ
| сНоменклатура.ЭтоГруппа = ЛОЖЬ";
фМассивТаблицаНоменклатуры = Запрос.Выполнить().Выгрузить();
КонецЕсли;
Отказ = Ложь;
Если фКоличествоРодителей < 1 Тогда
Отказ = Истина;
КонецЕсли;
Если Не Отказ Тогда
Если ТипЗнч(фМассивТаблицаНоменклатуры) = Тип("Массив") Тогда
ТаблицаНоменклатуры = Новый ТаблицаЗначений;
ТаблицаНоменклатуры.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТаблицаНоменклатуры.ЗагрузитьКолонку(фМассивТаблицаНоменклатуры, "Номенклатура");
ТаблицаНоменклатуры.Индексы.Добавить("Номенклатура");
Для индекс = 0 по фКоличествоРодителей Цикл
ТаблицаНоменклатуры.Колонки.Добавить("НоменклатураРодитель" + индекс, Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
КонецЦикла;
ТаблицаНоменклатуры.ЗагрузитьКолонку(фМассивТаблицаНоменклатуры, "НоменклатураРодитель0");
ИначеЕсли ТипЗнч(фМассивТаблицаНоменклатуры) = Тип("ТаблицаЗначений") Тогда
ТаблицаНоменклатуры = фМассивТаблицаНоменклатуры;
Если ТаблицаНоменклатуры.Колонки.Найти("Номенклатура") = Неопределено Тогда
Отказ = Истина;
КонецЕсли;
Если Не Отказ Тогда
ТаблицаНоменклатуры.Индексы.Добавить("Номенклатура");
Для индекс = 0 по фКоличествоРодителей Цикл
Если ТаблицаНоменклатуры.Колонки.Найти("НоменклатураРодитель" + индекс) = Неопределено Тогда
ТаблицаНоменклатуры.Колонки.Добавить("НоменклатураРодитель" + индекс, Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
Если индекс = 0 Тогда
ТаблицаНоменклатуры.ЗагрузитьКолонку(ТаблицаНоменклатуры.ВыгрузитьКолонку("Номенклатура"), "НоменклатураРодитель0");
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Иначе
Отказ = Истина;
КонецЕсли;
КонецЕсли;
Если Отказ Тогда
Возврат фМассивТаблицаНоменклатуры;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| тзНоменклатура.Номенклатура КАК Номенклатура,
| тзНоменклатура.НоменклатураРодитель0 КАК НоменклатураРодитель0
|ПОМЕСТИТЬ втДанные
|ИЗ
| &тзНоменклатура КАК тзНоменклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗРЕШЕННЫЕ
| втДанные.Номенклатура КАК Номенклатура,
| втДанные.НоменклатураРодитель0 КАК НоменклатураРодитель,
| ЕСТЬNULL(сНоменклатура.Родитель, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)) КАК НовыйРодитель
|ИЗ
| втДанные КАК втДанные
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК сНоменклатура
| ПО втДанные.НоменклатураРодитель0 = сНоменклатура.Ссылка
|ГДЕ
| втДанные.НоменклатураРодитель0 <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
|;
|
|////////////////////////////////////////////////////////////////////////////////
|УНИЧТОЖИТЬ втДанные";
Запрос.УстановитьПараметр("тзНоменклатура", ТаблицаНоменклатуры);
Выборка = Запрос.Выполнить().Выбрать();
КонецРекурсии = Истина;
Если УровеньРекурсии < 15 Тогда // Защита от бесконечного цикла
Пока Выборка.Следующий() Цикл
тзСтроки = ТаблицаНоменклатуры.НайтиСтроки(Новый Структура("Номенклатура", Выборка.Номенклатура));
Для Каждого тзСтрока из тзСтроки Цикл
Если УровеньРекурсии > 0 Тогда // Нет смысла перезаполнять родителей на первом этапе рекурсии, при малой вложенности справочника нельзя копировать значение НоменклатураРодитель0
индекс = фКоличествоРодителей;
Пока индекс > 0 Цикл
тзСтрока["НоменклатураРодитель" + индекс] = тзСтрока["НоменклатураРодитель" + (индекс - 1)];
индекс = индекс - 1;
КонецЦикла;
КонецЕсли;
тзСтрока.НоменклатураРодитель0 = Выборка.НовыйРодитель;
Если ЗначениеЗаполнено(тзСтрока.НоменклатураРодитель0) Тогда
КонецРекурсии = Ложь;
КонецЕсли;
//Здесь можно что-то вычислять, вызывать доп. функции и т.д.
КонецЦикла;
КонецЦикла;
КонецЕсли;
Если КонецРекурсии Тогда
ТаблицаНоменклатуры.Колонки.Удалить("НоменклатураРодитель0");
Иначе
УровеньРекурсии = УровеньРекурсии + 1;
ТаблицаНоменклатуры = ПолучитьТаблицуРодителейНоменклатурыРекурсией(ТаблицаНоменклатуры, фКоличествоРодителей, УровеньРекурсии);
КонецЕсли;
Возврат ТаблицаНоменклатуры;
КонецФункции