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