Как заменить одну номенклатуру на другую в документах 1С с помощью внешней обработки?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Причина ошибки: разница между ссылкой и объектом

Проанализируем исходный фрагмент кода, вызвавший исключение:


&НаСервере
Процедура ЗаменитьНаСервере(ДокументСсылка, НоменклатураДляЗамены, НоваяНоменклатура)
    Тов = ДокументСсылка.Товары;
    Для Каждого Стр Из Тов Цикл
        Если Стр.Номенклатура = НоменклатураДляЗамены Тогда
            Стр.Номенклатура = НоваяНоменклатура; // Ошибка: Поле объекта недоступно для записи
        КонецЕсли;
    КонецЦикла;
    ДокументСсылка.Записать(РежимЗаписиДокумента.Проведение);
КонецПроцедуры

Выясним причину ошибки: переменная ДокументСсылка содержит значение ссылочного типа (например, ДокументСсылка.РеализацияТоваровУслуг). Ссылочные типы данных в платформе 1С:Предприятие предназначены исключительно для чтения и навигации по данным информационной базы. Через ссылку можно прочитать реквизиты документа или строки его табличной части, но любые попытки изменить значения полей или вызвать метод записи приведут к ошибке.

Для изменения данных документа необходимо получить его объектную форму с помощью метода ПолучитьОбъект(). Только тип ДокументОбъект предоставляет доступ к модификации реквизитов, табличных частей и позволяет сохранять изменения в базе данных.

Правильная реализация замены номенклатуры

Рассмотрим базовый исправленный вариант процедуры, в котором выполняется получение объекта, обход табличной части и последующая запись:


&НаСервере
Процедура ЗаменитьНаСервере(ДокументСсылка, НоменклатураДляЗамены, НоваяНоменклатура)
    // Получаем объект для редактирования
    ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
    
    Если ДокументОбъект = Неопределено Тогда
        Возврат; // Документ мог быть удален другим пользователем
    КонецЕсли;
    
    БылИзменен = Ложь;
    
    Для Каждого Стр Из ДокументОбъект.Товары Цикл
        Если Стр.Номенклатура = НоменклатураДляЗамены Тогда
            Стр.Номенклатура = НоваяНоменклатура;
            БылИзменен = Истина;
        КонецЕсли;
    КонецЦикла;
    
    // Записываем документ только в том случае, если были внесены изменения
    Если БылИзменен Тогда
        ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
    КонецЕсли;
КонецПроцедуры

Сопутствующие учетные нюансы при замене номенклатуры

Простая замена ссылки на номенклатуру в строке табличной части решает только синтаксическую задачу. В реальных конфигурациях (1С:ERP, 1С:Комплексная автоматизация, 1С:Управление торговлей, 1С:Бухгалтерия) номенклатура связана с множеством зависимых реквизитов. Разберем важные моменты, на которые следует обратить внимание:

  1. Единицы измерения и коэффициенты: У новой номенклатуры может отличаться базовая единица хранения или коэффициент пересчета. Если не обновить реквизит ЕдиницаИзмерения (или Коэффициент), итоговое количественное выражение в складских отчетах станет некорректным.
  2. Характеристики и серии: Если у старой номенклатуры велся учет по характеристикам или сериям, прямая замена номенклатуры оставит в строке ссылку на характеристику старой позиции, что нарушит ссылочную целостность (так как справочник характеристик подчинен конкретной номенклатуре). В таком случае реквизиты Характеристика и Серия необходимо очищать или сопоставлять заново.
  3. Счета учета и ставки НДС: В бухгалтерских конфигурациях счета учета (например, 10.01, 41.01, 43) и ставка НДС подтягиваются исходя из настроек номенклатуры. При смене категории или вида номенклатуры может потребоваться обновить и эти реквизиты.
  4. Контроль остатков при проведении: При вызове метода ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение) система выполняет стандартные проверки, включая контроль остатков на складе. Если новой номенклатуры недостаточно на остатке на дату документа, проведение завершится ошибкой.

Рекомендуемый шаблон с обработкой ошибок и транзакцией

Посмотрим на расширенный пример пакетной обработки, который учитывает дату запрета изменения данных, ошибки блокировок и позволяет изолировать сбой в одном документе от всего процесса:


&НаСервере
Процедура ЗаменитьНоменклатуруВМассивеДокументов(МассивСсылок, НоменклатураДляЗамены, НоваяНоменклатура)
    Для Каждого Ссылка Из МассивСсылок Цикл
        Попытка
            ДокументОбъект = Ссылка.ПолучитьОбъект();
            
            Если ДокументОбъект = Неопределено Тогда
                Продолжить;
            КонецЕсли;
            
            Модифицирован = Ложь;
            
            Для Каждого СтрокаТЧ Из ДокументОбъект.Товары Цикл
                Если СтрокаТЧ.Номенклатура = НоменклатураДляЗамены Тогда
                    СтрокаТЧ.Номенклатура = НоваяНоменклатура;
                    
                    // При необходимости обновляем единицу измерения из новой номенклатуры
                    Если ДокументОбъект.Товары.Колонки.Найти("ЕдиницаИзмерения") <> Неопределено Тогда
                        СтрокаТЧ.ЕдиницаИзмерения = НоваяНоменклатура.ЕдиницаИзмерения;
                    КонецЕсли;
                    
                    Модифицирован = Истина;
                КонецЕсли;
            КонецЦикла;
            
            Если Модифицирован Тогда
                // Если документ уже был проведен, проводим заново, иначе просто сохраняем
                Если ДокументОбъект.Проведен Тогда
                    ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
                Иначе
                    ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
                КонецЕсли;
            КонецЕсли;
            
        Исключение
            // Фиксируем ошибку и продолжаем обработку остальных документов
            ТекстОшибки = СтрШаблон("Ошибка при обработке документа %1: %2", 
                Строка(Ссылка), ОписаниеОшибки());
            ЗаписьЖурналаРегистрации("ЗаменаНоменклатуры", УровеньЖурналаРегистрации.Ошибка,,, ТекстОшибки);
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

Альтернативные типовые инструменты

Если нет необходимости писать собственный алгоритм с уникальной логикой заполнения реквизитов, рекомендуется использовать стандартные средства «Библиотеки стандартных подсистем» (БСП):

  1. Обработка «Поиск и замена дублей»: Позволяет объединить дублирующиеся элементы номенклатуры во всей информационной базе с автоматической заменой ссылок во всех документах и регистрах.
  2. Групповое изменение реквизитов: Позволяет выполнять отбор документов по критериям и пакетно изменять реквизиты табличных частей без написания программного кода.
← На главную