Как преобразовать элемент справочника в группу и почему возникает ошибка «Поле объекта недоступно для записи (ЭтоГруппа)»?

Программист
← На главную

В процессе работы с данными в 1С часто возникает задача реорганизации структуры справочников. Одна из таких задач — преобразование существующих элементов в группы для создания иерархии. Например, у нас есть плоский список в справочнике «Номенклатурные группы», и каждый элемент этого списка должен стать самостоятельной группой. Давайте разберемся, как правильно подойти к этой задаче и почему стандартная обработка «Групповое изменение реквизитов» не помогает, выдавая ошибку.

Анализ проблемы: почему стандартный инструмент не работает?

Первая мысль, которая приходит в голову, — использовать штатную обработку «Групповое изменение реквизитов». Кажется логичным, что можно выбрать нужные элементы и установить для них некий признак, отвечающий за тип «группа». В 1С таким признаком является свойство ЭтоГруппа.

Пользователь попытался выполнить код:

Объект.ЭтоГруппа = Истина;

В результате система выдала вполне ожидаемую ошибку: «Поле объекта недоступно для записи (ЭтоГруппа)». Давайте выясним причину.

Свойство ЭтоГруппа — это не обычный реквизит, который можно менять по своему усмотрению. Это системный атрибут объекта, который определяет его фундаментальный тип: является ли он конечным элементом или контейнером (группой) для других элементов. Этот атрибут задается один раз в момент создания объекта функцией СоздатьЭлемент() или СоздатьГруппу() и в дальнейшем доступен только для чтения. Платформа 1С:Предприятие не позволяет на лету менять природу уже существующего объекта в базе данных. Это сделано для обеспечения целостности данных.

Таким образом, «превратить» элемент в группу простым присвоением значения невозможно. Необходимо использовать другой подход.

Правильное решение: создание новых групп и перенос данных

Единственный верный способ решить нашу задачу — это написать небольшую внешнюю обработку, которая будет выполнять последовательность действий для каждого преобразуемого элемента. Стандартные средства здесь бессильны, так как требуется не изменение, а создание новых объектов с переносом информации.

Рассмотрим по шагам, как должна работать такая обработка.

  1. Выбор исходных данных

    В форме обработки необходимо разместить поле для выбора элементов из справочника «Номенклатурные группы», которые мы хотим преобразовать. Это может быть табличное поле с возможностью множественного выбора.

  2. Итерация по выбранным элементам

    Основной алгоритм будет выполняться в цикле по каждому выбранному элементу. Для каждого элемента мы будем создавать новую группу.

  3. Создание новой группы

    Внутри цикла для каждого исходного элемента нужно создать новый объект — группу. Для этого используется метод СоздатьГруппу() менеджера нужного справочника.

    
    // Получаем ссылку на текущий элемент из выборки
    СсылкаНаЭлемент = ВыбранныеЭлементы[i]; 
    
    // Создаем объект новой группы
    НоваяГруппа = Справочники.НоменклатурныеГруппы.СоздатьГруппу();
    
  4. Перенос реквизитов

    Чтобы новая группа была похожа на старый элемент, необходимо перенести значения всех значимых реквизитов. Как минимум, это Наименование. Если есть другие реквизиты (например, Комментарий, какие-то аналитические признаки), их тоже нужно скопировать.

    
    // Получаем объект старого элемента, чтобы прочитать его реквизиты
    ОбъектЭлемента = СсылкаНаЭлемент.ПолучитьОбъект();
    
    // Копируем данные
    НоваяГруппа.Наименование = ОбъектЭлемента.Наименование;
    // Если есть другие реквизиты, копируем и их
    // НоваяГруппа.Комментарий = ОбъектЭлемента.Комментарий; 
    // НоваяГруппа.ДругойРеквизит = ОбъектЭлемента.ДругойРеквизит;
    
    // Также важно сохранить положение в иерархии
    НоваяГруппа.Родитель = ОбъектЭлемента.Родитель;
    
  5. Запись новой группы

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

    
    Попытка
        НоваяГруппа.Записать();
    Исключение
        Сообщить("Не удалось записать новую группу для элемента: " + ОбъектЭлемента.Наименование);
        Продолжить; // Переходим к следующему элементу в цикле
    КонецПопытки;
    
  6. Обработка старого элемента и ссылочной целостности

    Это самый важный и критический этап. После того как мы создали новую группу, у нас в системе существуют два объекта: старый элемент и новая группа. Что делать дальше, зависит от задачи. Но самое главное — это сохранить целостность данных. Если на старый элемент ссылались какие-либо документы или другие справочники, простое его удаление приведет к «битым» ссылкам и ошибкам в системе.

    Проанализируем два основных сценария:

    Сценарий А: Полная замена элемента на группу

    Этот сценарий подходит, если старый элемент больше не нужен и все ссылки на него должны теперь указывать на новую группу.

    1. Пометка на удаление. Старый элемент помечается на удаление.
    2. ОбъектЭлемента.УстановитьПометкуУдаления(Истина);
    3. Замена ссылок. ОБЯЗАТЕЛЬНО! После выполнения обработки необходимо запустить стандартный инструмент «Поиск и замена значений» (находится в разделе «Администрирование» -> «Обслуживание» -> «Корректировка данных»). В этой обработке нужно указать, что мы ищем все ссылки на старый, помеченный на удаление элемент, и заменяем их на ссылку на новую, только что созданную группу. Эту операцию нужно проделать для каждой пары «старый элемент — новая группа». Если элементов много, можно автоматизировать и этот процесс, но это уже более сложная задача.

    Сценарий Б: Создание иерархии

    Этот сценарий подходит, если задача — не просто заменить элемент, а сделать его дочерним по отношению к одноименной группе. Например, была «Номенклатурная группа А», а должна стать группа «Номенклатурная группа А», внутри которой лежит элемент «Номенклатурная группа А».

    1. Установка родителя. У старого элемента нужно изменить родителя, указав в качестве него ссылку на новую группу.
    2. 
      // Ссылку на новую группу мы получили после ее записи
      ОбъектЭлемента.Родитель = НоваяГруппа.Ссылка;
      ОбъектЭлемента.Записать();
      

      В этом случае замена ссылок не требуется, так как старый объект не удаляется, а лишь меняет свое место в иерархии. Все документы, которые на него ссылались, продолжат это делать корректно.

Пример кода для обработки

Рассмотрим итоговый пример кода, который реализует полную замену элемента на группу (Сценарий А). Этот код можно вставить в кнопку «Выполнить» на форме вашей обработки.


&НаСервере
Процедура ПреобразоватьЭлементыВГруппы(ВыбранныеЭлементы)

    Для Каждого СсылкаНаЭлемент Из ВыбранныеЭлементы Цикл
        
        ОбъектЭлемента = СсылкаНаЭлемент.ПолучитьОбъект();
        
        // 1. Создаем новую группу
        НоваяГруппа = Справочники.НоменклатурныеГруппы.СоздатьГруппу();
        
        // 2. Переносим реквизиты
        НоваяГруппа.Наименование = ОбъектЭлемента.Наименование;
        НоваяГруппа.Родитель = ОбъектЭлемента.Родитель;
        // Перенос других реквизитов...
        
        // 3. Записываем новую группу
        Попытка
            НоваяГруппа.Записать();
        Исключение
            Сообщение = Новый СообщениеПользователю;
            Сообщение.Текст = "Не удалось создать группу для элемента '" + ОбъектЭлемента.Наименование + "'. " + ОписаниеОшибки();
            Сообщение.Сообщить();
            Продолжить;
        КонецПопытки;
        
        // 4. Помечаем старый элемент на удаление
        ОбъектЭлемента.УстановитьПометкуУдаления(Истина);
        
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Для элемента '" + ОбъектЭлемента.Наименование + "' создана группа. Старый элемент помечен на удаление.";
        Сообщение.Сообщить();

    КонецЦикла;
    
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = "Обработка завершена. ВАЖНО: теперь запустите обработку 'Поиск и замена значений' для обновления ссылок на созданные группы!";
    Сообщение.Сообщить();

КонецПроцедуры

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

← На главную