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