Разработка и Конфигурация · 11 мин
Как программно создать группу номенклатуры в 1С
Как программно создать группу номенклатуры в 1С: код для обычных и управляемых форм, назначение родителя, проверка дублей, типичные ошибки и FAQ.
Группа номенклатуры — это элемент-«папка» справочника «Номенклатура», внутри которого размещаются товары и услуги. Программное создание групп требуется при загрузке данных из Excel и внешних систем, при обмене между базами, при первоначальном заполнении справочника или массовой реорганизации каталога. Во всех этих случаях ручное заведение папок отнимает время и провоцирует ошибки в иерархии.
Механика создания группы почти не отличается от создания обычного элемента справочника, но есть важные нюансы: у группы не заполняются характеристики учёта (вид номенклатуры, единица измерения, ставка НДС), для неё используется метод СоздатьГруппу() вместо СоздатьЭлемент(), а при назначении родителя нужно контролировать, что родитель — тоже группа, иначе запись завершится ошибкой.
Ниже разобраны готовые фрагменты кода для типовых конфигураций (УТ, ERP, Бухгалтерия), способы поиска и назначения родительской группы, проверка на дубли, а также типичные ошибки, из-за которых группы не создаются или «теряются» в иерархии.
Базовый код создания группы номенклатуры
Минимальный сценарий — создать группу верхнего уровня без родителя. Для этого достаточно получить менеджер справочника, вызвать СоздатьГруппу(), заполнить наименование и записать объект:
НоваяГруппа = Справочники.Номенклатура.СоздатьГруппу();
НоваяГруппа.Наименование = "Строительные материалы";
НоваяГруппа.Записать();
Сообщить("Создана группа: " + НоваяГруппа.Ссылка);
Метод Записать() возвращает управление после фиксации объекта в базе; если запись прошла успешно, свойство Ссылка уже содержит ссылку на новую группу. Если группа с таким наименованием не требуется уникальной — никаких дополнительных проверок платформа не выполнит, дубли по наименованию технически допустимы, поэтому контроль ложится на разработчика.
Обратите внимание: у группы недоступна часть реквизитов элемента. Попытка заполнить, например, ВидНоменклатуры или ЕдиницаИзмерения у объекта-группы либо вызовет ошибку, либо будет проигнорирована — зависит от конфигурации. Заполняйте только общие реквизиты: Наименование, Родитель, Описание и пользовательские реквизиты, для которых в конфигураторе разрешено использование у групп.
Создание группы внутри родительской папки
На практике группы почти всегда вложены друг в друга: «Товары → Электроника → Ноутбуки». Чтобы создать подгруппу, нужно сначала получить ссылку на родительскую группу — поиском по наименованию или по известному коду — и присвоить её свойству Родитель.
РодительскаяГруппа = Справочники.Номенклатура.НайтиПоНаименованию("Электроника", Истина);
Если РодительскаяГруппа.Пустая() Тогда
ВызватьИсключение "Родительская группа не найдена";
КонецЕсли;
Если Не РодительскаяГруппа.ЭтоГруппа Тогда
ВызватьИсключение "Найден элемент, а не группа";
КонецЕсли;
НоваяГруппа = Справочники.Номенклатура.СоздатьГруппу();
НоваяГруппа.Наименование = "Ноутбуки";
НоваяГруппа.Родитель = РодительскаяГруппа;
НоваяГруппа.Записать();
Второй параметр НайтиПоНаименованию со значением Истина означает поиск по точному совпадению. Без него платформа ищет по началу наименования, что при похожих названиях («Электроника» и «Электроника промышленная») может вернуть не ту папку. Для надёжности всегда используйте точный поиск либо ищите по коду, если коды ведутся осмысленно.
Если родительская группа ещё не создана, логично добавить функцию «получить или создать»: сначала искать, при отсутствии — создавать и возвращать ссылку. Такой подход делает загрузку иерархии устойчивой к порядку следования данных.
- 1Найдите родительскую группу через НайтиПоНаименованию с точным совпадением
- 2Проверьте, что найденный объект не пустой и ЭтоГруппа = Истина
- 3Создайте объект методом СоздатьГруппу() и заполните Наименование
- 4Присвойте свойству Родитель ссылку на родительскую группу
- 5Вызовите Записать() и проверьте, что Ссылка заполнена
- 6Откройте справочник в интерфейсе и убедитесь, что группа появилась в нужной ветке
Проверка на дубли перед созданием
Платформа не запрещает две группы с одинаковым наименованием в одной папке, но для учёта это почти всегда проблема: пользователи кладут товары в разные «одинаковые» папки, отчёты дробятся, обмены создают новые дубли при каждом сеансе. Поэтому перед созданием группу стоит искать.
Простой вариант — поиск по наименованию с учётом родителя. Метод НайтиПоНаименованию принимает третьим параметром ссылку на родителя, что позволяет различать одинаковые папки в разных ветках:
Функция ПолучитьИлиСоздатьГруппу(Наименование, Родитель = Неопределено)
Найденная = Справочники.Номенклатура.НайтиПоНаименованию(
Наименование, Истина, Родитель);
Если Не Найденная.Пустая() И Найденная.ЭтоГруппа Тогда
Возврат Найденная;
КонецЕсли;
НоваяГруппа = Справочники.Номенклатура.СоздатьГруппу();
НоваяГруппа.Наименование = Наименование;
Если Родитель <> Неопределено Тогда
НоваяГруппа.Родитель = Родитель;
КонецЕсли;
НоваяГруппа.Записать();
Возврат НоваяГруппа.Ссылка;
КонецФункции
Для обменов с внешними системами надёжнее искать не по наименованию, а по уникальному внешнему идентификатору — например, хранить GUID источника в дополнительном реквизите или в регистре соответствия. Наименования в источнике могут меняться, и поиск по ним начнёт плодить дубли.
Массовое создание групп из таблицы данных
Типовая задача — построить иерархию из таблицы значений, загруженной из Excel или CSV, где для каждой строки указаны наименование группы и наименование её родителя. Ключевой момент: родительская группа должна существовать к моменту создания дочерней, поэтому данные либо сортируют по уровню вложенности, либо обрабатывают рекурсивно.
Удобный приём — кэшировать уже созданные группы в соответствии, чтобы не искать одну и ту же папку запросом много раз. Это заметно ускоряет обработку на объёмах в тысячи позиций:
КэшГрупп = Новый Соответствие;
Для Каждого Строка Из ТаблицаГрупп Цикл
Ключ = Строка.Родитель + "/" + Строка.Наименование;
Если КэшГрупп[Ключ] <> Неопределено Тогда
Продолжить;
КонецЕсли;
СсылкаГруппы = ПолучитьИлиСоздатьГруппу(
Строка.Наименование, КэшГрупп[Строка.Родитель]);
КэшГрупп.Вставить(Ключ, СсылкаГруппы);
КонецЦикла;
Если обработка выполняется вне транзакции и падает на середине, часть групп уже записана. При повторном запуске функция «получить или создать» подхватит существующие папки, поэтому такие обработки естественно получаются идемпотентными — безопасными для повторного выполнения. Для разовых сложных загрузок дополнительно можно обернуть весь цикл в транзакцию через НачатьТранзакцию() и ЗафиксироватьТранзакцию().
Отличия в управляемых формах и на сервере
В управляемом приложении код создания группы должен выполняться на сервере: объекты справочников недоступны на тонком клиенте. Обработку оформляют с директивой &НаСервере, а при вызове из клиентской процедуры передают только примитивные данные — наименования, строки таблицы.
Сам код записи идентичен показанному выше — разница только в контексте исполнения. Если обработка работает в файловой базе в толстом клиенте, ограничений нет. Также учитывайте права: у пользователя, под которым выполняется код, должны быть права на добавление элементов справочника «Номенклатура», иначе Записать() вызовет исключение нарушения прав доступа.
В конфигурациях с подсистемой БСП (Библиотека стандартных подсистем) наименование может формироваться обработчиками заполнения, а запись — проходить проверки заполнения. Если группа не записывается без видимой причины, посмотрите текст исключения: часто там сообщение о незаполненном обязательном реквизите, добавленном доработкой.
Как проверить результат
Папка отображается в нужной ветке иерархии
Группа есть в поиске, но не в ожидаемой папке — ошибка в Родителе
ЭтоГруппа = Истина
Ложь — создан элемент, а не группа, товары в него не сгруппируются
Дублей не появляется, используются существующие группы
Создаются повторные папки с тем же наименованием
Записывается без исключений
Ошибка нарушения прав доступа — нужно настроить роли
Альтернативные способы получения иерархии
Программное создание — не единственный путь. Разовую иерархию проще построить руками в интерфейсе: кнопка «Создать группу» в форме списка справочника. Для загрузки из табличного документа в типовых конфигурациях есть обработка «Загрузка данных из табличного документа», которая умеет создавать и группы, и элементы без программирования.
Сравнение вариантов
Подходит для нескольких папок; не масштабируется и требует ручной выверки иерархии
Подходит для разовой загрузки из Excel без доработок; гибкость ограничена настройками обработки
Подходит для обменов, регулярных загрузок и сложной логики; требует разработки и тестирования на копии
Выбор зависит от частоты задачи. Разовая структура на десяток папок не оправдывает написания обработки. Регулярный обмен с сайтом или поставщиком, наоборот, требует устойчивого программного механизма с поиском по внешнему идентификатору и журналированием ошибок.
Что важно запомнить
Группа создаётся методом СоздатьГруппу(), обязательные данные — Наименование и при необходимости Родитель. Перед созданием ищите существующую группу по точному наименованию в рамках родителя, проверяйте ЭтоГруппа у родителя и тестируйте массовые обработки на копии базы.
Частые вопросы
Чем группа отличается от элемента справочника «Номенклатура»?
Группа — это папка для организации иерархии: в ней нельзя вести учёт остатков, ей не назначаются вид номенклатуры, единица измерения и ставка НДС. Элемент — это конкретный товар или услуга. Создаются они разными методами: СоздатьГруппу() и СоздатьЭлемент(), и взаимно преобразовать их после записи нельзя.
Почему Записать() выдаёт ошибку при назначении родителя?
Чаще всего родителем назначен обычный элемент, а не группа — платформа это запрещает. Проверьте свойство ЭтоГруппа у ссылки-родителя. Вторая причина — попытка назначить родителем саму создаваемую группу или её потомка, что образует цикл в иерархии.
Можно ли создать группу вне транзакции при массовой загрузке?
Можно, и часто так делают намеренно: если обработка построена по принципу «найти или создать», повторный запуск после сбоя просто продолжит с места остановки. Транзакция нужна, когда требуется «всё или ничего» — например, при финансово значимой реорганизации справочника.
Как найти группу, если наименования в базе и в файле отличаются регистром или пробелами?
НайтиПоНаименованию с точным совпадением чувствителен к строке, поэтому перед поиском нормализуйте обе стороны: СокрЛП() для удаления лишних пробелов и при необходимости ВРег() для сравнения без учёта регистра. Надёжнее всего сопоставлять по внешнему коду или GUID, а не по наименованию.
Работает ли этот код во внешней обработке на управляемых формах?
Да, но код создания должен выполняться в серверной процедуре (директива &НаСервере), поскольку объекты справочников недоступны на тонком клиенте. Из клиентской части передавайте на сервер только строки и таблицы значений, а ссылки получайте обратно как результат вызова.
Как удалить ошибочно созданные группы?
Группу можно пометить на удаление через ПолучитьОбъект() и УстановитьПометкуУдаления(Истина), если в ней нет элементов и подгрупп. Если иерархия большая, сначала переместите содержимое в правильные папки, затем пометьте лишние группы и выполните штатное удаление помеченных объектов с контролем ссылочной целостности.