← Назад к вопросам
Механизм состава изделия с вложенностью
3.0 Senior🔥 121 комментариев
#Запросы и оптимизация#Конфигурации и типовые
Условие
Реализуйте механизм состава изделия (BOM — Bill of Materials) с минимум 2 уровнями вложенности.
Требования:
- Справочник "Номенклатура" с табличной частью "Состав" (компоненты и их количество)
- Рекурсивный расчёт потребности в материалах
- Отчёт по потребности материалов для изготовления изделия
Пример
Изделие "Стол":
- Столешница (1 шт.)
- Доска (3 шт.)
- Лак (0.5 л)
- Ножка (4 шт.)
- Брус (1 шт.)
Для изготовления 2 столов потребуется:
- Доска: 6 шт.
- Лак: 1 л
- Брус: 8 шт.
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Структура справочника Номенклатура
Реквизиты
- Наименование (Строка)
- ТипНоменклатуры (Перечисление): Изделие, Компонент, Материал
- ЕдиницаИзмерения (Справочник.ЕдиницыИзмерения)
- Цена (Число, 12,2)
Табличная часть "Состав"
- Компонент (Справочник.Номенклатура) - ссылка на компонент
- Количество (Число, 10,3) - количество компонента
- ЕдиницаИзмерения (Справочник.ЕдиницыИзмерения)
- Примечание (Строка, неполное)
Функция расчёта потребности материалов (рекурсивная)
Функция ПолучитьПотребностьМатериалов(Номенклатура, Количество = 1) Экспорт
ТаблицаПотребности = Новый ТаблицаЗначений();
ТаблицаПотребности.Колонки.Добавить("Компонент", , "Справочник.Номенклатура");
ТаблицаПотребности.Колонки.Добавить("НаименованиеКомпонента", , "Строка");
ТаблицаПотребности.Колонки.Добавить("Количество", , "Число");
ТаблицаПотребности.Колонки.Добавить("ЕдиницаИзмерения", , "Справочник.ЕдиницыИзмерения");
ТаблицаПотребности.Колонки.Добавить("Уровень", , "Число");
РазвернутьСтруктуруИзделия(Номенклатура, Количество, ТаблицаПотребности, 0);
Возврат ТаблицаПотребности;
КонецФункции
Процедура РазвернутьСтруктуруИзделия(Номенклатура, Количество, ТаблицаПотребности, Уровень)
НоменклатураОбъект = Номенклатура.ПолучитьОбъект();
// Если нет состава — это материал
Если НоменклатураОбъект.Состав.Количество() = 0 Тогда
ДобавитьВТаблицуПотребности(Номенклатура, НоменклатураОбъект.Наименование, Количество, НоменклатураОбъект.ЕдиницаИзмерения, Уровень, ТаблицаПотребности);
Возврат;
КонецЕсли;
// Проходим по компонентам
Для каждого СтрокаСостава Из НоменклатураОбъект.Состав Цикл
КоличествоКомпонента = СтрокаСостава.Количество * Количество;
РазвернутьСтруктуруИзделия(СтрокаСостава.Компонент, КоличествоКомпонента, ТаблицаПотребности, Уровень + 1);
КонецЦикла;
КонецПроцедуры
Процедура ДобавитьВТаблицуПотребности(Компонент, НаименованиеКомпонента, Количество, ЕдиницаИзмерения, Уровень, ТаблицаПотребности)
// Проверяем, есть ли уже такой компонент
ФильтрПоиска = Новый Структура("Компонент", Компонент);
НайденныеСтроки = ТаблицаПотребности.НайтиСтроки(ФильтрПоиска);
Если НайденныеСтроки.Количество() > 0 Тогда
// Суммируем количество
НайденныеСтроки[0].Количество = НайденныеСтроки[0].Количество + Количество;
Иначе
// Добавляем новую строку
НоваяСтрока = ТаблицаПотребности.Добавить();
НоваяСтрока.Компонент = Компонент;
НоваяСтрока.НаименованиеКомпонента = НаименованиеКомпонента;
НоваяСтрока.Количество = Количество;
НоваяСтрока.ЕдиницаИзмерения = ЕдиницаИзмерения;
НоваяСтрока.Уровень = Уровень;
КонецЕсли;
КонецПроцедуры
Запрос для отчёта потребности материалов
Функция ПолучитьОтчётПотребностиМатериалов(Изделие, КоличествоИзделий) Экспорт
ТаблицаПотребности = ПолучитьПотребностьМатериалов(Изделие, КоличествоИзделий);
// Фильтруем только материалы (без промежуточных изделий)
ОтфильтрованнаяТаблица = ТаблицаПотребности.Скопировать();
Возврат ОтфильтрованнаяТаблица;
КонецФункции
Процедура вывода отчёта
Процедура ВывестиОтчётПотребности(Изделие, КоличествоИзделий)
ТаблицаПотребности = ПолучитьПотребностьМатериалов(Изделие, КоличествоИзделий);
Сообщить("Потребность для изготовления " + КоличествоИзделий + " изделия(й): " + Изделие.Наименование);
Сообщить("");
Для каждого Строка Из ТаблицаПотребности Цикл
ОтступОтступ = Формат(Строка.Уровень * 2, "00") + " ";
Сообщить(ОтступОтступ + "- " + Строка.НаименованиеКомпонента + ": " + Строка.Количество + " " + ?(Строка.ЕдиницаИзмерения <> Неопределено, Строка.ЕдиницаИзмерения.Аббревиатура, ""));
КонецЦикла;
КонецПроцедуры
Альтернатива: с использованием запроса (БОМ дерево)
Функция ПостроитьБОМДерево(Номенклатура, Количество) Экспорт
ДеревоБОМ = Новый ДеревоЗначений();
ДеревоБОМ.Колонки.Добавить("Компонент", , "Справочник.Номенклатура");
ДеревоБОМ.Колонки.Добавить("Наименование", , "Строка");
ДеревоБОМ.Колонки.Добавить("Количество", , "Число");
ДеревоБОМ.Колонки.Добавить("ЕдиницаИзмерения", , "Строка");
КорневаяСтрока = ДеревоБОМ.Строки.Добавить();
КорневаяСтрока.Компонент = Номенклатура;
КорневаяСтрока.Наименование = Номенклатура.Наименование;
КорневаяСтрока.Количество = Количество;
КорневаяСтрока.ЕдиницаИзмерения = Номенклатура.ЕдиницаИзмерения.Аббревиатура;
РекурсивноПостроитьДерево(Номенклатура, Количество, КорневаяСтрока);
Возврат ДеревоБОМ;
КонецФункции
Процедура РекурсивноПостроитьДерево(Номенклатура, Количество, РодительскаяСтрока)
НоменклатураОбъект = Номенклатура.ПолучитьОбъект();
Для каждого СтрокаСостава Из НоменклатураОбъект.Состав Цикл
НоваяСтрока = РодительскаяСтрока.Строки.Добавить();
НоваяСтрока.Компонент = СтрокаСостава.Компонент;
НоваяСтрока.Наименование = СтрокаСостава.Компонент.Наименование;
НоваяСтрока.Количество = СтрокаСостава.Количество * Количество;
НоваяСтрока.ЕдиницаИзмерения = СтрокаСостава.ЕдиницаИзмерения.Аббревиатура;
РекурсивноПостроитьДерево(СтрокаСостава.Компонент, СтрокаСостава.Количество * Количество, НоваяСтрока);
КонецЦикла;
КонецПроцедуры
Пример использования
// Для примера: Стол -> Столешница -> Доска, Лак; Ножка -> Брус
Запросил = Новый Запрос();
Стол = ПолучитьНоменклатуруПоНаименованию("Стол");
// Метод 1: простой расчёт
ТаблицаПотребности = ПолучитьПотребностьМатериалов(Стол, 2);
ДляКаждого Строка Из ТаблицаПотребности Цикл
Сообщить(Строка.НаименованиеКомпонента + ": " + Строка.Количество);
КонецЦикла;
// Метод 2: дерево
ДеревоБОМ = ПостроитьБОМДерево(Стол, 2);
// Для вывода в UI
ВывестиОтчётПотребности(Стол, 2);
Ключевые моменты
- Рекурсия — обход всех уровней вложенности
- Суммирование компонентов — одинаковые компоненты считаются вместе
- Расширяемость — легко добавить уровни
- Дерево значений — отображение иерархии в UI
- Перемножение количеств — каждый уровень на каждый компонент