При работе с конфигурациями 1С, такими как "Комплексная автоматизация 1.1", часто возникает необходимость программного изменения данных. Одной из таких задач может быть дозаполнение или обновление свойств для существующих характеристик номенклатуры. Рассмотрим подробнее, как мы можем решить эту задачу, избегая распространенных ошибок и добиваясь корректного обновления всех необходимых данных.
Наша цель — добавить новое свойство "Вес 1м,кг" со значением "22" для всех характеристик определенной номенклатурной позиции и убедиться, что наименования этих характеристик автоматически обновятся, включив в себя новое значение.
Одна из частых ошибок, с которой мы сталкиваемся при работе с типовыми конфигурациями 1С, — это путаница между свойствами самой номенклатуры и свойствами ее характеристик. Эти сущности хранятся в одном и том же регистре сведений ЗначенияСвойствОбъектов, но ссылаются на разные объекты:
Объект регистра ЗначенияСвойствОбъектов должна быть указана ссылка на элемент справочника Номенклатура.Объекта необходимо указывать ссылку на элемент справочника ХарактеристикиНоменклатуры.В нашем случае, поскольку требуется заполнить свойство для каждой из характеристик, мы должны использовать ссылку на конкретную характеристику как Объект при записи в регистр сведений.
Прежде всего, нам необходимо найти ссылку на само свойство, которое мы хотим заполнить, и создать (или найти) его значение. Допустим, мы хотим добавить свойство "Вес 1м,кг" и установить для него значение "22".
Сначала мы находим нужное свойство в плане видов характеристик СвойстваОбъектов:
ВесХарактеристика = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Вес 1м,кг");
Если ВесХарактеристика = Неопределено Тогда
Сообщить("Свойство 'Вес 1м,кг' не найдено. Проверьте правильность наименования.");
Возврат;
КонецЕсли;
Затем создаем или находим элемент справочника ЗначенияСвойствОбъектов, который будет хранить наше значение "22". Важно, чтобы владельцем этого значения было само свойство "Вес 1м,кг".
// Попытаемся найти существующее значение "22" для свойства "Вес 1м,кг"
ЗначениеИзСправочника = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("22", ВесХарактеристика);
// Если значение не найдено, создадим его
Если ЗначениеИзСправочника = Неопределено Тогда
СоздЭлементСпр = Справочники.ЗначенияСвойствОбъектов.СоздатьЭлемент();
СоздЭлементСпр.Владелец = ВесХарактеристика;
СоздЭлементСпр.Наименование = "22";
Попытка
СоздЭлементСпр.Записать();
ЗначениеИзСправочника = СоздЭлементСпр.Ссылка;
Сообщить("Создано новое значение свойства '22'.", СтатусСообщения.Информация);
Исключение
Сообщить("Ошибка при записи значения свойства: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
Возврат;
КонецПопытки;
Иначе
Сообщить("Значение свойства '22' уже существует.", СтатусСообщения.Информация);
КонецЕсли;
Если ЗначениеИзСправочника = Неопределено Тогда
Сообщить("Не удалось получить или создать значение свойства. Операция прервана.", СтатусСообщения.Ошибка);
Возврат;
КонецЕсли;
Переменная Ном в приведенных примерах кода подразумевает ссылку на элемент справочника Номенклатура, для которого мы обрабатываем характеристики.
Чтобы обновить свойства всех характеристик, нам необходимо их получить. Мы можем сделать это с помощью запроса к справочнику ХарактеристикиНоменклатуры, отбирая записи по владельцу (поле Владелец), в котором указываем нашу номенклатуру.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХарактеристикиНоменклатуры.Ссылка КАК СсылкаНаХар,
| ХарактеристикиНоменклатуры.Наименование
|ИЗ
| Справочник.ХарактеристикиНоменклатуры КАК ХарактеристикиНоменклатуры
|ГДЕ
| ХарактеристикиНоменклатуры.Владелец = &Владелец
| И ХарактеристикиНоменклатуры.ПометкаУдаления = ЛОЖЬ";
Запрос.УстановитьПараметр("Владелец", Ном);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Теперь, когда у нас есть выборка всех характеристик, мы можем перебрать их в цикле и для каждой характеристики записать новое значение свойства в регистр сведений ЗначенияСвойствОбъектов. Для этого мы будем использовать МенеджерЗаписи.
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// Создаем менеджер записи для регистра сведений "ЗначенияСвойствОбъектов"
РегистрЗначенияСвойствОбъектов = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
// Устанавливаем значение нового свойства
РегистрЗначенияСвойствОбъектов.Значение = ЗначениеИзСправочника;
// Внимание: Объект - это ссылка на ТЕКУЩУЮ ХАРАКТЕРИСТИКУ, а не на номенклатуру
РегистрЗначенияСвойствОбъектов.Объект = ВыборкаДетальныеЗаписи.СсылкаНаХар;
// Указываем, какое свойство мы заполняем
РегистрЗначенияСвойствОбъектов.Свойство = ВесХарактеристика;
// Записываем запись в регистр сведений
Попытка
РегистрЗначенияСвойствОбъектов.Записать();
Сообщить("Для характеристики " + ВыборкаДетальныеЗаписи.Наименование + " (ссылка: " + ВыборкаДетальныеЗаписи.СсылкаНаХар + ") успешно добавлено свойство '" + ВесХарактеристика.Наименование + " = " + ЗначениеИзСправочника.Наименование + "'.", СтатусСообщения.Информация);
Исключение
Сообщить("Ошибка при записи свойства для характеристики " + ВыборкаДетальныеЗаписи.Наименование + ": " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
КонецПопытки;
// ... Продолжение следует для обновления наименования ...
КонецЦикла;
В этом блоке кода ключевым моментом является строка РегистрЗначенияСвойствОбъектов.Объект = ВыборкаДетальныеЗаписи.СсылкаНаХар;. Здесь мы четко указываем, что свойство относится к текущей характеристике, а не к номенклатуре.
После того как мы записали новое свойство для характеристики в регистр сведений, ее наименование в справочнике ХарактеристикиНоменклатуры автоматически не изменится. Наименование характеристики часто формируется на основе значений всех ее свойств. Чтобы обновить его, нам необходимо выполнить следующие действия:
Дополним наш цикл следующим кодом:
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// ... (код из Шага 3 по записи свойства) ...
// После записи свойства, получаем все свойства текущей характеристики
// для формирования ее наименования.
Запрос = Новый Запрос();
Запрос.Текст = "ВЫБРАТЬ
| ЗначенияСвойствОбъектов.Свойство,
| ЗначенияСвойствОбъектов.Значение,
| Ложь КАК ПометкаУдаления
|ИЗ
| РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
|ГДЕ
| ЗначенияСвойствОбъектов.Объект = &Объект";
Запрос.УстановитьПараметр("Объект", ВыборкаДетальныеЗаписи.СсылкаНаХар);
ТаблицаСвойств = Запрос.Выполнить().Выгрузить();
// Получаем объект характеристики для изменения ее наименования
ОбъектХар = ВыборкаДетальныеЗаписи.СсылкаНаХар.ПолучитьОбъект();
// Формируем новое наименование, используя стандартную функцию конфигурации
ОбъектХар.Наименование = ОбъектХар.СформироватьНаименование(ТаблицаСвойств);
// Записываем обновленный объект характеристики
Попытка
ОбъектХар.Записать();
Сообщить("Наименование характеристики '" + ВыборкаДетальныеЗаписи.Наименование + "' успешно обновлено на: '" + ОбъектХар.Наименование + "'.", СтатусСообщения.Информация);
Исключение
Сообщить("Ошибка при обновлении наименования характеристики " + ВыборкаДетальныеЗаписи.Наименование + ": " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
КонецПопытки;
КонецЦикла;
Объединив все шаги, мы получаем следующий рабочий код, который можно использовать для программного дозаполнения свойства "Вес 1м,кг" для всех характеристик номенклатуры и обновления их наименований:
// Предполагаем, что переменная "Ном" уже содержит ссылку на элемент справочника "Номенклатура",
// для которого мы хотим обновить характеристики.
// Например: Ном = Справочники.Номенклатура.НайтиПоНаименованию("Труба моя тест");
// Если Ном = Неопределено Тогда
// Сообщить("Номенклатура не найдена!");
// Возврат;
// КонецЕсли;
// Шаг 1: Подготавливаем свойство и его значение
ВесХарактеристика = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Вес 1м,кг");
Если ВесХарактеристика = Неопределено Тогда
Сообщить("Свойство 'Вес 1м,кг' не найдено. Проверьте правильность наименования.", СтатусСообщения.Ошибка);
Возврат;
КонецЕсли;
// Попытаемся найти существующее значение "22" для свойства "Вес 1м,кг"
ЗначениеИзСправочника = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("22", ВесХарактеристика);
// Если значение не найдено, создадим его
Если ЗначениеИзСправочника = Неопределено Тогда
СоздЭлементСпр = Справочники.ЗначенияСвойствОбъектов.СоздатьЭлемент();
СоздЭлементСпр.Владелец = ВесХарактеристика;
СоздЭлементСпр.Наименование = "22";
Попытка
СоздЭлементСпр.Записать();
ЗначениеИзСправочника = СоздЭлементСпр.Ссылка;
Сообщить("Создано новое значение свойства '22'.", СтатусСообщения.Информация);
Исключение
Сообщить("Ошибка при записи значения свойства: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
Возврат;
КонецПопытки;
Иначе
Сообщить("Значение свойства '22' уже существует.", СтатусСообщения.Информация);
КонецЕсли;
Если ЗначениеИзСправочника = Неопределено Тогда
Сообщить("Не удалось получить или создать значение свойства. Операция прервана.", СтатусСообщения.Ошибка);
Возврат;
КонецЕсли;
// Шаг 2: Получаем все характеристики для заданной номенклатуры
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХарактеристикиНоменклатуры.Ссылка КАК СсылкаНаХар,
| ХарактеристикиНоменклатуры.Наименование
|ИЗ
| Справочник.ХарактеристикиНоменклатуры КАК ХарактеристикиНоменклатуры
|ГДЕ
| ХарактеристикиНоменклатуры.Владелец = &Владелец
| И ХарактеристикиНоменклатуры.ПометкаУдаления = ЛОЖЬ";
Запрос.УстановитьПараметр("Владелец", Ном);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Сообщить("Для номенклатуры '" + Ном + "' не найдено активных характеристик. Операция завершена.", СтатусСообщения.Информация);
Возврат;
КонецЕсли;
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Сообщить("Начинаем обработку характеристик номенклатуры '" + Ном + "'.", СтатусСообщения.Информация);
// Шаг 3 и 4: Перебираем характеристики, добавляем свойство и обновляем наименование
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// Шаг 3: Записываем новое свойство в регистр сведений "ЗначенияСвойствОбъектов"
РегистрЗначенияСвойствОбъектов = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
РегистрЗначенияСвойствОбъектов.Значение = ЗначениеИзСправочника;
РегистрЗначенияСвойствОбъектов.Объект = ВыборкаДетальныеЗаписи.СсылкаНаХар; // Ссылка на текущую характеристику
РегистрЗначенияСвойствОбъектов.Свойство = ВесХарактеристика;
Попытка
РегистрЗначенияСвойствОбъектов.Записать();
Сообщить(" -> Для характеристики '" + ВыборкаДетальныеЗаписи.Наименование + "' успешно добавлено свойство '" + ВесХарактеристика.Наименование + " = " + ЗначениеИзСправочника.Наименование + "'.", СтатусСообщения.Информация);
Исключение
Сообщить(" -> Ошибка при записи свойства для характеристики '" + ВыборкаДетальныеЗаписи.Наименование + "': " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
Продолжить; // Переходим к следующей характеристике
КонецПопытки;
// Шаг 4: Обновляем наименование характеристики
ЗапросДляНаименования = Новый Запрос();
ЗапросДляНаименования.Текст = "ВЫБРАТЬ
| ЗначенияСвойствОбъектов.Свойство,
| ЗначенияСвойствОбъектов.Значение,
| Ложь КАК ПометкаУдаления
|ИЗ
| РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
|ГДЕ
| ЗначенияСвойствОбъектов.Объект = &Объект";
ЗапросДляНаименования.УстановитьПараметр("Объект", ВыборкаДетальныеЗаписи.СсылкаНаХар);
ТаблицаСвойств = ЗапросДляНаименования.Выполнить().Выгрузить();
ОбъектХар = ВыборкаДетальныеЗаписи.СсылкаНаХар.ПолучитьОбъект();
// Старое наименование для сравнения в сообщении
СтароеНаименование = ОбъектХар.Наименование;
// СформироватьНаименование - это метод объекта СправочникОбъект.ХарактеристикиНоменклатуры
// Он пересчитывает наименование на основе текущих свойств
ОбъектХар.Наименование = ОбъектХар.СформироватьНаименование(ТаблицаСвойств);
Попытка
ОбъектХар.Записать();
Если СтароеНаименование <> ОбъектХар.Наименование Тогда
Сообщить(" -> Наименование характеристики обновлено с '" + СтароеНаименование + "' на '" + ОбъектХар.Наименование + "'.", СтатусСообщения.Информация);
Иначе
Сообщить(" -> Наименование характеристики '" + СтароеНаименование + "' не изменилось (возможно, свойство не влияет на наименование или уже было учтено).", СтатусСообщения.Информация);
КонецЕсли;
Исключение
Сообщить(" -> Ошибка при обновлении наименования характеристики '" + СтароеНаименование + "': " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
КонецПопытки;
КонецЦикла;
Сообщить("Процесс обработки всех характеристик завершен.", СтатусСообщения.Информация);
Мы рассмотрели комплексное решение задачи по программному заполнению нового свойства для характеристик номенклатуры и автоматическому обновлению их наименований. Ключевыми моментами, которые нам помогли, были правильное определение Объекта при работе с регистром ЗначенияСвойствОбъектов (ссылка на характеристику, а не на номенклатуру) и вызов метода СформироватьНаименование() для объекта характеристики с последующей его записью. Этот подход позволяет добиться желаемого результата в конфигурации "1С:Комплексная автоматизация 1.1" и аналогичных системах.