Как программно изменить единицу измерения в 1С:Розница 2.3 и почему это может не работать?

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

В практике разработчика 1С часто возникает задача массовой корректировки данных, например, заполнение пустых единиц измерения в справочнике Номенклатура после некорректного импорта из внешних систем. Казалось бы, задача тривиальна: прочитать файл Excel, найти ссылку на товар и записать новое значение в реквизит. Однако в современных конфигурациях, таких как 1С:Розница 2.3, Управление торговлей 11 или ERP 2, архитектура хранения данных о единицах измерения значительно сложнее, чем в старых решениях на обычных формах.

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

Анализ исходной проблемы и кода

Рассмотрим ситуацию: программист пытается загрузить единицы измерения (шт) для списка номенклатуры из табличного документа. Код выглядит следующим образом:


ЕИ = Справочники.БазовыеЕдиницыИзмерения.НайтиПоНаименованию("шт");
Для НомерСтроки = 1 По (КоличествоСтрок) Цикл 
    Ном = Справочники.Номенклатура.НайтиПоКоду(ТабДок.Область("R" + Формат(НомерСтроки, "ЧГ=0") + "C" + 1).Текст);
    НомОбъект = Ном.ПолучитьОбъект(); 
    НомОбъект.ЕдиницаИзмерения = ЕИ;  
    Попытка
        НомОбъект.Записать();
    Исключение
        Сообщить(НомОбъект.Наименование + " " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

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

Причина №1: Влияние наборов упаковок

Выясним главную причину, с которой столкнулся автор темы. В 1С:Розница 2.3 существует реквизит НаборУпаковок. Если этот реквизит заполнен, система переходит в режим использования упаковок. В этом случае ЕдиницаИзмерения (базовая единица по ОКЕИ) жестко связана с иерархией упаковок. Если у товара установлен конкретный набор упаковок, программная попытка изменить базовую единицу измерения может конфликтовать с уже настроенными коэффициентами в этом наборе.

Важный нюанс: если в карточке товара включено использование индивидуальных упаковок, то базовая единица становится фундаментом для всех расчетов коэффициентов. Изменение фундамента при наличии "надстроек" (упаковок) может быть заблокировано программными проверками в модуле объекта номенклатуры, чтобы не допустить нарушения логики учета (например, когда 1 коробка внезапно станет состоять не из 10 штук, а из 10 килограммов).

Причина №2: Особенности поиска в классификаторах

Посмотрим на строку поиска единицы измерения: Справочники.БазовыеЕдиницыИзмерения.НайтиПоНаименованию("шт"). Профессиональная разработка требует избегать поиска по наименованию в государственных классификаторах. Почему это плохо?

  1. В базе может быть несколько элементов с наименованием "шт" (например, созданный вручную и загруженный из классификатора).
  2. Наименование может отличаться: "шт", "шт.", "ШТ", "Штука".
  3. Правильнее использовать поиск по коду ОКЕИ. Для штук это код 796.

Рассмотрим правильный вариант поиска:


ЕИ = Справочники.БазовыеЕдиницыИзмерения.НайтиПоКоду("796");
Если ЕИ.Пустая() Тогда
    // Если по коду не нашли, можно попробовать найти по международному сокращению или создать
    // Но лучше убедиться, что классификатор заполнен
КонецЕсли;

Причина №3: Механизм защиты реквизитов

В современных конфигурациях реализован механизм "Разрешение редактирования реквизитов объектов". Если у номенклатуры есть движения по регистрам (остатки, продажи), система блокирует изменение ключевых полей, таких как ЕдиницаИзмерения, ТипНоменклатуры или СтатусУказанияСерий.

При использовании метода Записать() в коде, если не приняты специальные меры, могут сработать проверки, которые просто "откатят" значение реквизита к исходному в момент выполнения подписок на события. Чтобы обойти эти проверки (если вы уверены в своих действиях), необходимо использовать флаг обмена данными.

Как решить проблему: правильный алгоритм

Проанализируем исправленный и безопасный подход к решению задачи. Нам нужно не просто присвоить значение, но и гарантировать его запись, учитывая специфику "Розницы 2.3".

Шаг 1: Проверка нахождения объекта

Всегда проверяйте, найдена ли ссылка функцией НайтиПоКоду или НайтиПоНаименованию. Если ссылка пустая, метод ПолучитьОбъект() вернет Неопределено или вызовет ошибку.

Шаг 2: Использование режима загрузки

Для массового изменения реквизитов в существующих карточках используйте свойство ОбменДанными.Загрузка = Истина. Это отключает большинство проверок в модулях объекта и подписках, позволяя записать данные даже если по товару уже были движения. Внимание: используйте это осторожно, так как это может привести к несоответствию единиц измерения в документах прошлых периодов и текущих остатках.

Шаг 3: Обработка наборов упаковок

Если вы меняете единицу измерения, убедитесь, что реквизит НаборУпаковок либо пуст, либо соответствует новой единице. В идеале, если набор упаковок заполнен, его нужно проанализировать или очистить.

Рассмотрим улучшенный пример кода:


// Предварительно найдем единицу измерения по коду ОКЕИ
СсылкаЕИ = Справочники.БазовыеЕдиницыИзмерения.НайтиПоКоду("796");

Если СсылкаЕИ.Пустая() Тогда
    Сообщить("Единица измерения 'шт' (код 796) не найдена в классификаторе!");
    Возврат;
КонецЕсли;

Для НомерСтроки = 1 По КоличествоСтрок Цикл 
    ТекстКода = ТабДок.Область("R" + Формат(НомерСтроки, "ЧГ=0") + "C1").Текст;
    СсылкаНом = Справочники.Номенклатура.НайтиПоКоду(ТекстКода);
    
    Если СсылкаНом.Пустая() Тогда
        Сообщить("Товар с кодом " + ТекстКода + " не найден");
        Продолжить;
    КонецЕсли;
    
    ОбъектНом = СсылкаНом.ПолучитьОбъект();
    
    // Проверяем, не заполнено ли уже правильное значение
    Если ОбъектНом.ЕдиницаИзмерения = СсылкаЕИ Тогда
        Продолжить;
    КонецЕсли;
    
    ОбъектНом.ЕдиницаИзмерения = СсылкаЕИ;
    
    // Если мешает НаборУпаковок, как в случае автора темы, его можно очистить
    // (Только если это допустимо бизнес-логикой!)
    // ОбъектНом.НаборУпаковок = Справочники.НаборыУпаковок.ПустаяСсылка();
    
    // Включаем режим загрузки для обхода проверок защиты реквизитов
    ОбъектНом.ОбменДанными.Загрузка = Истина;
    
    Попытка
        ОбъектНом.Записать();
    Исключение
        Сообщить("Ошибка записи товара '" + ОбъектНом.Наименование + "': " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

Последствия изменения для учета

Проанализируем, к чему может привести такое изменение в живой базе 1С:Розница. Единица измерения в карточке товара — это не просто текст, это ссылка, которая используется в:

Таким образом, мы выяснили, что причина "неудачных" записей в 1С:Розница 2.3 кроется во взаимосвязи объектов. Рекомендуем всегда проверять заполнение реквизитов НаборУпаковок и использовать ОбменДанными.Загрузка = Истина при массовых корректировках справочников, предварительно сделав резервную копию базы данных.

← На главную