Как настроить автоматическое заполнение контрагента при выборе контактного лица

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В разработке на платформе 1С:Предприятие 8 часто возникает задача повышения юзабилити форм. Одна из типичных ситуаций: пользователь выбирает в документе контактное лицо, и система должна автоматически определить, к какому контрагенту относится этот человек, чтобы заполнить соответствующее поле. Это не только ускоряет ввод данных, но и минимизирует количество ошибок. Давайте подробно разберем, как реализовать этот механизм, используя программный код и встроенные возможности платформы.

Анализ структуры данных

Прежде чем приступать к написанию кода, проанализируем, как связаны данные в вашей конфигурации. В классической архитектуре 1С справочник КонтактныеЛица обычно является подчиненным справочнику Контрагенты. Это означает, что у каждого элемента контактного лица есть стандартный реквизит Владелец, в котором и хранится ссылка на нужную нам организацию.

Однако в более современных конфигурациях, таких как УТ 11, ERP 2 или КА 2, структура может быть сложнее. Там контактные лица часто привязаны к справочнику Партнеры. В этом случае цепочка поиска будет выглядеть так: Контактное лицо -> Партнер -> Контрагент. Мы рассмотрим универсальный подход, который можно адаптировать под любую структуру.

Шаг 1. Создание обработчика события на форме

Первым делом нам необходимо отследить момент, когда пользователь меняет значение в поле контактного лица. Для этого используется событие ПриИзменении. Разберем по шагам, как это сделать:

  1. Откройте форму документа в Конфигураторе.
  2. Выберите элемент формы (поле ввода), связанный с реквизитом КонтактноеЛицо.
  3. В панели свойств найдите список событий и нажмите на лупу рядом с событием ПриИзменении.
  4. Система предложит создать процедуру на клиенте. Соглашаемся.

Рассмотрим пример кода, который будет располагаться в модуле формы:


&НаКлиенте
Процедура КонтактноеЛицоПриИзменении(Элемент)
    
    // Проверим, заполнено ли контактное лицо
    Если ЗначениеЗаполнено(Объект.КонтактноеЛицо) Тогда
        
        // Вызываем серверную функцию для получения данных
        КонтрагентВладелец = ПолучитьВладельцаКонтактногоЛица(Объект.КонтактноеЛицо);
        
        Если ЗначениеЗаполнено(КонтрагентВладелец) Тогда
            Объект.Контрагент = КонтрагентВладелец;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Реализация серверной логики

Поскольку данные справочников находятся в базе данных, нам необходимо обратиться к серверу. Здесь крайне важно соблюдать правила оптимизации. Выясним причину, почему лучше использовать директиву &НаСервереБезКонтекста. При обычном серверном вызове (&НаСервере) на сервер передается вся форма (весь контекст), что создает лишнюю нагрузку на сеть и замедляет работу. Использование бесконтекстного вызова позволяет передать только необходимые параметры.

Посмотрим на пример реализации серверной функции:


&НаСервереБезКонтекста
Функция ПолучитьВладельцаКонтактногоЛица(Знач КонтактноеЛицо)
    
    // Самый простой способ — получение через свойство Владелец
    // Однако в реальных задачах лучше использовать функции БСП
    Возврат КонтактноеЛицо.Владелец;
    
КонецФункции

Шаг 3. Использование Библиотеки стандартных подсистем (БСП)

Если ваша конфигурация построена на базе БСП (что является стандартом для большинства современных решений), рекомендуется использовать программный интерфейс общих модулей. Это работает быстрее и надежнее. Проанализируем ситуацию: метод ОбщегоНазначения.ЗначениеРеквизитаОбъекта() позволяет прочитать только одно поле из базы данных, не считывая весь объект целиком.

Обновим нашу функцию с использованием БСП:


&НаСервереБезКонтекста
Функция ПолучитьВладельцаКонтактногоЛица(Знач КонтактноеЛицо)
    
    // Используем БСП для быстрого получения значения реквизита
    // Это исключает лишнее обращение к объектным данным
    Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(КонтактноеЛицо, "Владелец");
    
КонецФункции

Шаг 4. Обработка сложных связей (Партнеры и Контрагенты)

Если в вашей программе используется разделение на Партнеров и Контрагентов, алгоритм усложняется. Нам нужно сначала найти партнера, а затем его основного контрагента. Разберем этот пример подробнее:


&НаСервереБезКонтекста
Функция ПолучитьКонтрагентаЧерезПартнера(Знач КонтактноеЛицо)
    
    // Получаем партнера, которому принадлежит контакт
    Партнер = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(КонтактноеЛицо, "Владелец");
    
    Если ЗначениеЗаполнено(Партнер) Тогда
        // Здесь может быть запрос к регистру сведений или справочнику
        // для поиска основного контрагента данного партнера
        // Для примера вернем пустое значение или результат поиска
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

Альтернативный метод: Связи параметров выбора

Иногда задачу можно решить вообще без написания кода, используя механизмы платформы в Конфигураторе. Это называется Связи параметров выбора. Рассмотрим, как это работает:

Если в документе порядок выбора обратный (сначала Контрагент, потом Контактное лицо), вы можете настроить свойство реквизита КонтактноеЛицо. В поле "Связи параметров выбора" укажите: Отбор.Владелец(Объект.Контрагент). После этого при открытии списка выбора контактных лиц система автоматически покажет только тех, кто относится к выбранному контрагенту.

Хотя этот метод решает задачу "отбора", он не помогает с "автозаполнением". Поэтому для задачи автоматической подстановки Контрагента при выборе Контактного лица программный метод, описанный выше, остается основным.

Важные рекомендации по UX и логике

При реализации автоматизации важно учитывать сценарии поведения пользователя. Давайте проанализируем несколько важных моментов:

Ниже представлен более продвинутый пример клиентской процедуры с учетом этих нюансов:


&НаКлиенте
Процедура КонтактноеЛицоПриИзменении(Элемент)
    
    Если Не ЗначениеЗаполнено(Объект.КонтактноеЛицо) Тогда
        Возврат;
    КонецЕсли;
    
    НайденныйВладелец = ПолучитьВладельцаКонтактногоЛица(Объект.КонтактноеЛицо);
    
    Если ЗначениеЗаполнено(НайденныйВладелец) Тогда
        // Проверяем, нужно ли менять текущего контрагента
        Если Объект.Контрагент <> НайденныйВладелец Тогда
            Объект.Контрагент = НайденныйВладелец;
            // Здесь же можно вызвать процедуру КонтрагентПриИзменении, 
            // если она содержит логику заполнения цен или договоров
            КонтрагентПриИзменении(Элементы.Контрагент);
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Таким образом, мы рассмотрели комплексный подход к автоматизации заполнения реквизитов. Комбинируя знания о структуре метаданных, оптимизированные серверные вызовы и возможности БСП, вы сможете создавать отзывчивые и удобные интерфейсы для пользователей 1С.

← На главную