При разработке в среде 1С:Предприятие 8.3, особенно в таких конфигурациях, как 1С:Управление нашей фирмой (УНФ), программисты часто сталкиваются с необходимостью извлечения данных, которые хранятся не в основных реквизитах справочника, а в механизме дополнительных свойств. Обычный подход через обращение к свойству объекта в данном случае не работает. В этой статье мы подробно разберем, почему стандартные методы поиска могут возвращать пустые значения, и научимся правильно извлекать дополнительные реквизиты программными средствами.
Рассмотрим ситуацию, с которой часто сталкиваются начинающие разработчики. При попытке получить значение через ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию(), мы получаем ссылку на сам элемент плана видов характеристик (ПВХ). Этот элемент является лишь "определением" или "метаданными" реквизита — он хранит название («Паспорт», «СНИЛС»), тип значения (Строка, Число) и другие настройки.
Однако само значение этого реквизита для конкретного контрагента хранится совершенно в другом месте. В 1С:УНФ (как и в других конфигурациях на базе БСП) значения дополнительных реквизитов находятся в табличной части справочника Контрагенты под названием ДополнительныеРеквизиты. Именно поэтому код, пытающийся получить ПаспортСерия.Значение напрямую из ПВХ, всегда будет возвращать пустой результат: у самого определения реквизита нет и не может быть значения «Серия паспорта».
Самый правильный и "цивилизованный" способ получения данных — использование программного интерфейса Библиотеки Стандартных Подсистем (БСП). Проанализируем работу с общим модулем УправлениеСвойствами. Этот метод хорош тем, что он автоматически учитывает особенности хранения данных (будь то реквизиты в табличной части или сведения в регистре).
Для реализации этого подхода нам сначала нужно получить ссылку на само свойство (реквизит), а затем запросить его значение для конкретного объекта. Рассмотрим пример кода, который можно разместить в процедуре заполнения на сервере:
&НаСервере
Процедура ЗаполнитьРеквизитыИзКонтрагента(СсылкаНаКонтрагента)
// Получаем ссылку на нужное свойство (доп. реквизит)
// Внимание: поиск по наименованию чувствителен к изменениям пользователя!
СвойствоПаспорт = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("ПаспортСерия (Контрагенты)");
Если Не СвойствоПаспорт.Пустая() Тогда
// Используем функцию БСП для получения значения
ЗначениеРеквизита = УправлениеСвойствами.ЗначениеСвойства(СсылкаНаКонтрагента, СвойствоПаспорт);
// Записываем результат в реквизит документа на форме
Объект.ПаспортСерияКонтрагента = ЗначениеРеквизита;
КонецЕсли;
КонецПроцедуры
Этот метод прост, но имеет недостаток: если нам нужно выгрузить 10–15 реквизитов (как в случае с паспортными данными), вызов функции в цикле или последовательно может замедлить работу системы из-за множественных обращений к базе данных.
Если нам необходимо получить сразу целый пакет данных (Серия, Номер, Кем выдан, Дата выдачи и т.д.), мы рекомендуем использовать запрос. Это наиболее производительный способ, так как мы обращаемся к базе данных один раз. Выясним, как составить такой запрос правильно.
Посмотрим на пример функции, которая возвращает структуру со всеми необходимыми данными:
&НаСервере
Функция ПолучитьПакетДопРеквизитов(КонтрагентСсылка)
Результат = Новый Структура;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КонтрагентыДополнительныеРеквизиты.Свойство.Наименование КАК ИмяСвойства,
| КонтрагентыДополнительныеРеквизиты.Значение КАК Значение
|ИЗ
| Справочник.Контрагенты.ДополнительныеРеквизиты КАК КонтрагентыДополнительныеРеквизиты
|ГДЕ
| КонтрагентыДополнительныеРеквизиты.Ссылка = &Контрагент";
Запрос.УстановитьПараметр("Контрагент", КонтрагентСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Здесь мы сопоставляем наименования из ПВХ с ключами нашей структуры
Если Найти(Выборка.ИмяСвойства, "ПаспортСерия") > 0 Тогда
Результат.Вставить("Серия", Выборка.Значение);
ИначеЕсли Найти(Выборка.ИмяСвойства, "ПаспортНомер") > 0 Тогда
Результат.Вставить("Номер", Выборка.Значение);
// ... и так далее для всех полей
КонецЕсли;
КонецЦикла;
Возвращает Результат;
КонецФункции
Обратите внимание на использование функции Найти() или точного соответствия строк. Поскольку в УНФ имена дополнительных реквизитов могут содержать уникальные идентификаторы (UID) после синхронизации с Битрикс24, поиск по точному вхождению подстроки может быть надежнее, чем полное совпадение.
Разберем еще один профессиональный метод. В БСП существует мощная функция УправлениеСвойствами.ЗначенияСвойствОбъекта(). Она возвращает таблицу значений, содержащую все заполненные дополнительные реквизиты объекта. Это избавляет нас от написания собственных запросов.
Проанализируем ситуацию применения:
&НаСервере
Процедура ЗаполнитьДанныеКонтрагентаНаФорме()
Если Объект.Контрагент.Пустая() Тогда
Возврат;
КонецЕсли;
// Получаем таблицу всех доп. реквизитов контрагента
ТаблицаСвойств = УправлениеСвойствами.ЗначенияСвойствОбъекта(Объект.Контрагент);
// Обходим таблицу и заполняем реквизиты документа
Для Каждого СтрокаСвойства Из ТаблицаСвойств Цикл
ИмяСвойства = Строка(СтрокаСвойства.Свойство);
Если Найти(ИмяСвойства, "ПаспортСерия") > 0 Тогда
Объект.ПаспортСерияКонтрагента = СтрокаСвойства.Значение;
ИначеЕсли Найти(ИмяСвойства, "ПаспортНомер") > 0 Тогда
Объект.ПаспортНомерКонтрагента = СтрокаСвойства.Значение;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Чтобы данные в документе «Согласие на ПНд» (персональных данных) заполнялись автоматически при выборе клиента, необходимо выполнить следующие действия:
ПриИзменении.Важный момент по безопасности типов: Дополнительные реквизиты имеют тип Характеристика.ДополнительныеРеквизитыИСведения. При получении значения (например, даты выдачи паспорта) всегда проверяйте, что тип полученного значения совпадает с типом реквизита в вашем документе. Если в доп. реквизите хранится ссылка на другой объект (например, на справочник "Банки"), а вы пытаетесь записать её в текстовое поле, используйте функцию Строка() для приведения типа.
Также стоит учесть нюанс именования. Если реквизиты созданы в Битрикс24 и переданы через синхронизацию, их имена в 1С часто выглядят как ПаспортСерия_545748a4.... В программном коде лучше избегать жесткой привязки к таким длинным именам с UID. Вместо этого можно создать настройку (например, в константах), где пользователь сам выберет, какой доп. реквизит считать "Серией паспорта", а какой — "Номером". Это сделает ваш код устойчивым к изменениям в настройках синхронизации.
Подводя итог, отметим, что работа с дополнительными реквизитами требует понимания структуры хранения данных БСП. Использование стандартных модулей УправлениеСвойствами делает ваш код совместимым с будущими обновлениями 1С:УНФ и значительно упрощает процесс разработки.