В процессе работы с данными в 1С часто возникает задача реорганизации структуры справочников. Одна из таких задач — преобразование существующих элементов в группы для создания иерархии. Например, у нас есть плоский список в справочнике «Номенклатурные группы», и каждый элемент этого списка должен стать самостоятельной группой. Давайте разберемся, как правильно подойти к этой задаче и почему стандартная обработка «Групповое изменение реквизитов» не помогает, выдавая ошибку.
Первая мысль, которая приходит в голову, — использовать штатную обработку «Групповое изменение реквизитов». Кажется логичным, что можно выбрать нужные элементы и установить для них некий признак, отвечающий за тип «группа». В 1С таким признаком является свойство ЭтоГруппа.
Пользователь попытался выполнить код:
Объект.ЭтоГруппа = Истина;
В результате система выдала вполне ожидаемую ошибку: «Поле объекта недоступно для записи (ЭтоГруппа)». Давайте выясним причину.
Свойство ЭтоГруппа — это не обычный реквизит, который можно менять по своему усмотрению. Это системный атрибут объекта, который определяет его фундаментальный тип: является ли он конечным элементом или контейнером (группой) для других элементов. Этот атрибут задается один раз в момент создания объекта функцией СоздатьЭлемент() или СоздатьГруппу() и в дальнейшем доступен только для чтения. Платформа 1С:Предприятие не позволяет на лету менять природу уже существующего объекта в базе данных. Это сделано для обеспечения целостности данных.
Таким образом, «превратить» элемент в группу простым присвоением значения невозможно. Необходимо использовать другой подход.
Единственный верный способ решить нашу задачу — это написать небольшую внешнюю обработку, которая будет выполнять последовательность действий для каждого преобразуемого элемента. Стандартные средства здесь бессильны, так как требуется не изменение, а создание новых объектов с переносом информации.
Рассмотрим по шагам, как должна работать такая обработка.
В форме обработки необходимо разместить поле для выбора элементов из справочника «Номенклатурные группы», которые мы хотим преобразовать. Это может быть табличное поле с возможностью множественного выбора.
Основной алгоритм будет выполняться в цикле по каждому выбранному элементу. Для каждого элемента мы будем создавать новую группу.
Внутри цикла для каждого исходного элемента нужно создать новый объект — группу. Для этого используется метод СоздатьГруппу() менеджера нужного справочника.
// Получаем ссылку на текущий элемент из выборки
СсылкаНаЭлемент = ВыбранныеЭлементы[i];
// Создаем объект новой группы
НоваяГруппа = Справочники.НоменклатурныеГруппы.СоздатьГруппу();
Чтобы новая группа была похожа на старый элемент, необходимо перенести значения всех значимых реквизитов. Как минимум, это Наименование. Если есть другие реквизиты (например, Комментарий, какие-то аналитические признаки), их тоже нужно скопировать.
// Получаем объект старого элемента, чтобы прочитать его реквизиты
ОбъектЭлемента = СсылкаНаЭлемент.ПолучитьОбъект();
// Копируем данные
НоваяГруппа.Наименование = ОбъектЭлемента.Наименование;
// Если есть другие реквизиты, копируем и их
// НоваяГруппа.Комментарий = ОбъектЭлемента.Комментарий;
// НоваяГруппа.ДругойРеквизит = ОбъектЭлемента.ДругойРеквизит;
// Также важно сохранить положение в иерархии
НоваяГруппа.Родитель = ОбъектЭлемента.Родитель;
После заполнения реквизитов новую группу необходимо записать в базу данных. Это действие зафиксирует новый объект и присвоит ему уникальную ссылку.
Попытка
НоваяГруппа.Записать();
Исключение
Сообщить("Не удалось записать новую группу для элемента: " + ОбъектЭлемента.Наименование);
Продолжить; // Переходим к следующему элементу в цикле
КонецПопытки;
Это самый важный и критический этап. После того как мы создали новую группу, у нас в системе существуют два объекта: старый элемент и новая группа. Что делать дальше, зависит от задачи. Но самое главное — это сохранить целостность данных. Если на старый элемент ссылались какие-либо документы или другие справочники, простое его удаление приведет к «битым» ссылкам и ошибкам в системе.
Проанализируем два основных сценария:
Этот сценарий подходит, если старый элемент больше не нужен и все ссылки на него должны теперь указывать на новую группу.
ОбъектЭлемента.УстановитьПометкуУдаления(Истина);
Этот сценарий подходит, если задача — не просто заменить элемент, а сделать его дочерним по отношению к одноименной группе. Например, была «Номенклатурная группа А», а должна стать группа «Номенклатурная группа А», внутри которой лежит элемент «Номенклатурная группа А».
// Ссылку на новую группу мы получили после ее записи
ОбъектЭлемента.Родитель = НоваяГруппа.Ссылка;
ОбъектЭлемента.Записать();
В этом случае замена ссылок не требуется, так как старый объект не удаляется, а лишь меняет свое место в иерархии. Все документы, которые на него ссылались, продолжат это делать корректно.
Рассмотрим итоговый пример кода, который реализует полную замену элемента на группу (Сценарий А). Этот код можно вставить в кнопку «Выполнить» на форме вашей обработки.
&НаСервере
Процедура ПреобразоватьЭлементыВГруппы(ВыбранныеЭлементы)
Для Каждого СсылкаНаЭлемент Из ВыбранныеЭлементы Цикл
ОбъектЭлемента = СсылкаНаЭлемент.ПолучитьОбъект();
// 1. Создаем новую группу
НоваяГруппа = Справочники.НоменклатурныеГруппы.СоздатьГруппу();
// 2. Переносим реквизиты
НоваяГруппа.Наименование = ОбъектЭлемента.Наименование;
НоваяГруппа.Родитель = ОбъектЭлемента.Родитель;
// Перенос других реквизитов...
// 3. Записываем новую группу
Попытка
НоваяГруппа.Записать();
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не удалось создать группу для элемента '" + ОбъектЭлемента.Наименование + "'. " + ОписаниеОшибки();
Сообщение.Сообщить();
Продолжить;
КонецПопытки;
// 4. Помечаем старый элемент на удаление
ОбъектЭлемента.УстановитьПометкуУдаления(Истина);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Для элемента '" + ОбъектЭлемента.Наименование + "' создана группа. Старый элемент помечен на удаление.";
Сообщение.Сообщить();
КонецЦикла;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Обработка завершена. ВАЖНО: теперь запустите обработку 'Поиск и замена значений' для обновления ссылок на созданные группы!";
Сообщение.Сообщить();
КонецПроцедуры
Вывод: не пытайтесь изменить системные свойства объектов, такие как ЭтоГруппа, напрямую. Правильный и безопасный путь всегда лежит через создание новых объектов нужного типа, аккуратный перенос данных и, что самое важное, корректную обработку ссылок на старые объекты для сохранения целостности информационной базы.