Как реализовать автозаполнение поля «Контактное лицо» в 1С при условии, что у контрагента только один контакт?

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

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

Разберем архитектуру данных и логику решения

Для начала проанализируем, где хранятся данные. В типовых конфигурациях, таких как «Управление нашей фирмой» (УНФ), информация о людях, связанных с организацией, хранится в справочнике КонтактныеЛица. Этот справочник является подчиненным справочнику Контрагенты. Это означает, что у каждой записи в КонтактныеЛица есть реквизит Владелец, который указывает на конкретного контрагента.

Нам необходимо написать алгоритм, который будет срабатывать в момент изменения поля Покупатель (или Контрагент) на форме документа. Мы воспользуемся следующим планом действий:

  1. Создадим обработчик события ПриИзменении для реквизита контрагента.
  2. Передадим управление на сервер, так как работа с базой данных через запросы возможна только в серверном контексте.
  3. Выполним запрос к справочнику контактов с фильтром по выбранному владельцу.
  4. Проверим количество полученных записей.
  5. Вернем результат на клиент и заполним поле формы.

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

Откроем форму документа и найдем реквизит Объект.Контрагент. В свойствах выберем событие ПриИзменении. Система предложит создать процедуру КонтрагентПриИзменении. Важно понимать, что эта процедура выполняется &НаКлиенте. Рассмотрим код вызова серверной функции:


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

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

Теперь проанализируем ситуацию на сервере. Нам нужно получить список всех контактов выбранного контрагента, которые не помечены на удаление. Выясним причину, почему не стоит использовать метод Выбрать() у справочника: запрос работает быстрее и позволяет сразу наложить все необходимые фильтры.

Посмотрим на пример функции, использующей объект Запрос:


&НаСервере
Функция НайтиЕдинственныйКонтактСервер(ВыбранныйКонтрагент)
    
    Запрос = Новый Запрос;
    // Мы выбираем ПЕРВЫЕ 2, чтобы оптимизировать работу базы. 
    // Если контактов 100, нам достаточно знать, что их больше одного.
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 2
        |	КонтактныеЛица.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник.КонтактныеЛица КАК КонтактныеЛица
        |ГДЕ
        |	КонтактныеЛица.Владелец = &Контрагент
        |	И НЕ КонтактныеЛица.ПометкаУдаления";
    
    Запрос.УстановитьПараметр("Контрагент", ВыбранныйКонтрагент);
    
    РезультатЗапроса = Запрос.Выполнить();
    Выгрузка = РезультатЗапроса.Выгрузить();
    
    // Проверяем условие задачи: ровно один контакт
    Если Выгрузка.Количество() = 1 Тогда
        Возврат Выгрузка[0].Ссылка;
    Иначе
        // Если контактов 0 или больше 1, возвращаем пустую ссылку
        Возврат Справочники.КонтактныеЛица.ПустаяСсылка();
    КонецЕсли;
    
КонецФункции

Важные замечания по типам данных

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

Важные моменты при работе с типами:

Альтернативный вариант через вложенный запрос

Рассмотрим ситуацию, предложенную в одном из сообщений форума, где используется соединение со справочником контрагентов. Это может быть полезно, если вам нужно получить контактное лицо, которое уже указано как «Основное» в карточке контрагента, но при этом соблюсти условие единственности. Посмотрим на структуру такого сложного запроса:


ВЫБРАТЬ
    ВЫБОР
        КОГДА КоличествоКонтактов.Всего = 1
            ТОГДА Контрагенты.КонтактноеЛицо
        ИНАЧЕ ЗНАЧЕНИЕ(Справочник.КонтактныеЛица.ПустаяСсылка)
    КОНЕЦ КАК КонтактноеЛицо
ИЗ
    Справочник.Контрагенты КАК Контрагенты
    ЛЕВОЕ СОЕДИНЕНИЕ (
        ВЫБРАТЬ
            КонтактныеЛица.Владелец КАК Владелец,
            КОЛИЧЕСТВО(КонтактныеЛица.Ссылка) КАК Всего
        ИЗ
            Справочник.КонтактныеЛица КАК КонтактныеЛица
        СГРУППИРОВАТЬ ПО
            КонтактныеЛица.Владелец) КАК КоличествоКонтактов
    ПО Контрагенты.Ссылка = КоличествоКонтактов.Владелец
ГДЕ
    Контрагенты.Ссылка = &Контрагент

Хотя такой запрос выглядит профессионально, для учебных целей и простых задач лучше использовать первый вариант (прямой запрос к справочнику контактов). Он проще в отладке и понимании. Выясним, почему: во втором варианте мы полагаемся на реквизит Контрагенты.КонтактноеЛицо (основной контакт), но если он не заполнен в карточке, даже при наличии единственного контакта в списке, система вернет пустоту.

Типичные ошибки при реализации

Проанализируем основные «грабли», на которые наступают начинающие разработчики 1С:

  1. Запрос по наименованию: Никогда не передавайте параметры в запрос по строке (например, Контрагенты.Наименование = &Имя). Всегда используйте ссылки (Ссылка = &Ссылка), так как наименования могут дублироваться или меняться.
  2. Отсутствие проверки на пустую ссылку: Перед выполнением запроса на сервере всегда проверяйте, передана ли ссылка на контрагента. Выполнение запроса с пустым параметром — лишняя нагрузка на систему.
  3. Использование Неопределено: В управляемых формах реквизиты ссылочного типа по умолчанию должны содержать пустую ссылку своего типа. Присваивание Неопределено может привести к тому, что в поле будет отображаться надпись «Объект не найден» или возникнут проблемы при записи документа.

Таким образом, мы рассмотрели полный цикл решения задачи: от анализа метаданных до написания кода клиент-серверного взаимодействия. Использование объекта Запрос и правильная обработка его результатов в процедуре ПриИзменении — это стандарт качества при разработке в среде 1С:Предприятие 8.

← На главную