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