При разработке в среде 1С:Предприятие 8.3, особенно в сложных конфигурациях вроде 1С:Комплексная автоматизация 2 или 1С:ERP, начинающие программисты часто сталкиваются с проблемой обращения к реквизитам ссылочного типа. Типичная ситуация: необходимо автоматически подставить определенное «Контактное лицо», если в документе «Заказ клиента» выбран конкретный «Партнер» (Клиент). В этой статье мы подробно разберем, как правильно работать со ссылками, почему нельзя сравнивать объект со строкой и как реализовать поиск с учетом владельца.
Рассмотрим ситуацию, с которой столкнулся автор темы. Попытка написать условие напрямую, используя строковое значение, приводит к тому, что код либо просто не срабатывает, либо вызывает ошибку выполнения. Проанализируем пример неправильного кода:
Если Объект.Партнер = "ООО Тест" Тогда Объект.КонтактноеЛицо = "ХХХ"; КонецЕсли;
Почему это не работает? В системе 1С реквизиты Партнер и КонтактноеЛицо имеют тип «Ссылка» (СправочникСсылка.Партнеры и СправочникСсылка.КонтактныеЛицаПартнеров соответственно). Ссылка — это уникальный идентификатор записи в базе данных (UUID), а не текст, который мы видим на экране. Строка «ООО Тест» — это лишь значение реквизита Наименование внутри объекта, на который указывает ссылка.
Для того чтобы обращение к реквизитам было корректным, нам необходимо либо сравнивать наименование объекта со строкой, либо (что более правильно) найти ссылку на нужный объект в справочнике и сравнивать уже две ссылки.
Самый простой способ, который часто применяется для оперативного решения задач, — это программный поиск ссылки по текстовому названию. Разберем по шагам, как это реализовать правильно на стороне сервера.
Во-первых, нам нужно найти саму компанию (Партнера). Во-вторых, нужно найти контактное лицо, которое принадлежит именно этой компании. Рассмотрим пример кода:
// Определяем названия, которые мы ищем
НаименованиеКлиента = "ООО Тест";
НазваниеКонтакта = "Иванов Иван Иванович";
// Находим ссылку на партнера
СсылкаНаКлиента = Справочники.Партнеры.НайтиПоНаименованию(НаименованиеКлиента);
// Проверяем, что партнер найден и совпадает с выбранным в документе
Если Объект.Партнер = СсылкаНаКлиента И Не СсылкаНаКлиента.Пустая() Тогда
// Ищем контактное лицо, ОХЗАТЕЛЬНО указывая владельца
// Третий параметр метода НайтиПоНаименованию — это владелец (Партнер)
СсылкаНаКонтакт = Справочники.КонтактныеЛицаПартнеров.НайтиПоНаименованию(НазваниеКонтакта, Ложь, СсылкаНаКлиента);
Если Не СсылкаНаКонтакт.Пустая() Тогда
Объект.КонтактноеЛицо = СсылкаНаКонтакт;
КонецЕсли;
КонецЕсли;
В данном примере мы используем метод НайтиПоНаименованию. Обратите внимание на важный нюанс: при поиске контактного лица мы передаем СсылкаНаКлиента в качестве третьего параметра. Это критически важно, так как в базе данных может быть несколько «Ивановых», работающих в разных компаниях. Без указания владельца система вернет первого попавшегося человека с таким именем.
Если нам нужно просто проверить условие, не выполняя поиск в справочнике, мы можем обратиться к реквизиту Наименование через точку от ссылки. Посмотрим на этот вариант:
Если Объект.Партнер.Наименование = "ООО Тест" Тогда
// Здесь должна быть логика поиска ссылки на контактное лицо,
// так как присвоить строку "ХХХ" в реквизит Ссылка нельзя.
КонецЕсли;
Важное предупреждение: Обращение через точку Объект.Партнер.Наименование заставляет систему выполнять неявный запрос к базе данных для получения этого поля. Если вы делаете это в цикле или при обработке большого количества данных, это может замедлить работу программы. Кроме того, если реквизит Партнер не заполнен (пустая ссылка), обращение к его наименованию в некоторых случаях может вернуть пустую строку, но лучше всегда проверять на Пустая().
Проанализируем специфику конфигурации КА 2. В этой системе разделены понятия Партнер и Контрагент:
Контактные лица в КА 2 привязываются именно к Партнеру. Поэтому при программной подстановке убедитесь, что вы ищете контакт в справочнике КонтактныеЛицаПартнеров, а в качестве владельца передаете именно ссылку из поля Партнер (или Клиент, в зависимости от имени реквизита в форме).
Использование жестко прописанных строк типа "ООО Тест" в коде считается плохой практикой (Hardcode). Если пользователь изменит название компании (например, добавит лишний пробел или изменит кавычки), ваш код перестанет работать. Рассмотрим более надежные способы реализации:
НайтиПоКоду("00001").Чтобы контактное лицо подставлялось сразу после того, как пользователь выбрал клиента, код необходимо разместить в модуле формы документа ЗаказКлиента. Для этого используется событие ПартнерПриИзменении.
Поскольку поиск в справочниках — это серверная операция, мы должны правильно распределить вызовы между клиентом и сервером:
&НаКлиенте
Процедура ПартнерПриИзменении(Элемент)
// Вызываем серверную процедуру для поиска и подстановки
ПодставитьКонтактноеЛицоНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПодставитьКонтактноеЛицоНаСервере()
Если Объект.Партнер.Наименование = "ООО Тест" Тогда
НаименованиеИскомогоКонтакта = "ХХХ";
СсылкаНаКонтакт = Справочники.КонтактныеЛицаПартнеров.НайтиПоНаименованию(
НаименованиеИскомогоКонтакта, Истина, Объект.Партнер
);
Если Не СсылкаНаКонтакт.Пустая() Тогда
Объект.КонтактноеЛицо = СсылкаНаКонтакт;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Использование параметра Истина во втором аргументе метода НайтиПоНаименованию гарантирует поиск по полному соответствию строки, что исключает ошибки, когда «ООО Тест» путается с «ООО Тест Плюс».
Мы проанализировали ситуацию и выяснили, что для корректной работы с реквизитами «Клиент» и «Контактное лицо» необходимо учитывать их ссылочную природу. Подведем итоги:
Истина для поиска по полному совпадению наименования.Пустая(), чтобы не затереть существующие данные пустым значением.Применяя эти правила, вы создадите надежный и отказоустойчивый код для автоматизации работы пользователей в 1С:Комплексная автоматизация 2.