Как подтянуть значение из справочника в документ в 1С 8.3

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

В процессе разработки в среде 1С:Предприятие 8.3 перед программистом часто возникает типовая задача: организовать автоматическое заполнение зависимых реквизитов документа при выборе основного значения. Например, когда пользователь выбирает в документе товар (реквизит справочника Номенклатура), система должна автоматически подставить его базовый цвет, артикул или единицу измерения. Другой классический пример — автоматическая установка ответственного лица или материально-ответственного лица (МОЛ) сразу после выбора склада отправления или поступления.

В этой статье мы подробно и по шагам разберем, как правильно реализовать данный механизм на управляемых формах. Мы проанализируем архитектурные особенности платформы 1С, выясним, почему прямое обращение к реквизитам «через точку» на клиенте является грубой ошибкой, и рассмотрим три профессиональных способа решения этой задачи.

Постановка задачи и анализ исходных данных

Представим, что у нас есть две похожие прикладные задачи:

  1. Кейс с товарами: В документе есть реквизиты Наименование (тип — ссылка на справочник Номенклатура) и Цвет. Требуется, чтобы при выборе наименования поле Цвет заполнялось автоматически значением, которое хранится в карточке этого товара.
  2. Кейс со складами: В документе есть реквизиты Склад (ссылка на справочник Склады) и ОтветственныйЗаПринятие. Требуется автоматически подтягивать ответственного сотрудника из карточки выбранного склада.

Давайте выясним, как решить эти задачи оптимально, безопасно для производительности системы и в соответствии со стандартами разработки фирмы «1С».

Проблема клиент-серверной архитектуры (Тонкий клиент)

Прежде чем писать код, давайте разберем критически важную особенность управляемого приложения 1С. Вся работа интерфейса происходит на клиенте (в тонком или веб-клиенте), в то время как непосредственная работа с базой данных и извлечение информации осуществляются на сервере.

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

Если мы напишем простой и очевидный код напрямую в клиентском обработчике:


&НаКлиенте
Процедура НаименованиеПриИзменении(Элемент)
    // Внимание! Это пример неоптимального кода, так делать не рекомендуется!
    Объект.Цвет = Объект.Наименование.Цвет; 
КонецПроцедуры

Система выполнит так называемый неявный (скрытый) серверный вызов. Платформа будет вынуждена приостановить работу интерфейса, обратиться к серверу, полностью прочитать весь объект справочника из базы данных в память, передать его обратно на клиент и только потом извлечь значение реквизита. Если у пользователя медленный интернет или сервер сильно загружен, форма начнет ощутимо зависать при каждом выборе товара. Давайте рассмотрим правильные методы обхода этой проблемы.

Способ 1. Реализация через тонкий серверный вызов без контекста

Наиболее правильный с точки зрения классического программирования способ — создание легкой серверной функции с директивой компиляции &НаСервереБезКонтекста. Она выполняет запрос к базе данных на сервере и возвращает только то конкретное значение, которое нам нужно, не гоняя лишний трафик между клиентом и сервером.

Разберем по шагам, как это реализовать:

  1. Откроем управляемую форму нашего документа в конфигураторе.
  2. Перейдем на вкладку «Элементы», найдем наше поле ввода (например, Наименование или Склад).
  3. В панели свойств элемента найдем событие ПриИзменении и нажмем на лупу для создания обработчика на клиенте.
  4. Напишем код вызова серверной функции и саму функцию получения данных.

Посмотрим на пример кода для автоматического заполнения цвета номенклатуры:


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

&НаСервереБезКонтекста
Функция ПолучитьЦветНоменклатуры(СсылкаНаНоменклатуру)
    
    // Платформа быстро считывает только один нужный реквизит из БД
    Возврат СсылкаНаНоменклатуру.Цвет;
    
КонецФункции

Теперь давайте проанализируем аналогичную реализацию для кейса со складом и ответственным лицом:


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

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

Способ 2. Использование функций Библиотеки Стандартных Подсистем (БСП)

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

Используя БСП, нам не нужно создавать свои собственные серверные функции &НаСервереБезКонтекста под каждый реквизит. Мы можем получить значение в одну строчку прямо в клиентском обработчике:


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

А что делать, если при изменении номенклатуры нам нужно вытащить сразу несколько показателей (например: цвет, артикул, ставку НДС и единицу измерения)? Делать 4 отдельных запроса к серверу непроизводительно. В БСП для этого предусмотрен метод получения множества реквизитов за один вызов, возвращающий структуру:


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

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

Способ 3. Визуальное отображение без написания кода (через «Путь к данным»)

Давайте проанализируем очень важную альтернативу. Задайте себе вопрос: а нужно ли хранить цвет или ответственного лица в самой таблице (базе данных) вашего документа?

Если эта информация нужна пользователю в документе исключительно для ознакомления и визуального контроля, а в самом документе дублировать её в базу данных нет необходимости, мы можем настроить это в конфигураторе вообще без написания кода!

Разберем, как вывести реквизит справочника на форму документа интерактивно:

  1. Откройте форму нужного документа в конфигураторе.
  2. В верхнем правом углу окна редактора формы перейдите на вкладку «Реквизиты».
  3. Найдите основной реквизит формы — Объект и раскройте его структуру (нажмите на значок «плюс»).
  4. В раскрывшемся списке найдите поле связи, например Наименование (или Склад) и также раскройте его по «плюсику». Перед вами откроются все доступные реквизиты этого справочника из базы данных.
  5. Найдите реквизит Цвет (или Ответственный) и просто перетащите его мышкой влево — в дерево элементов формы, расположив рядом с полем выбора номенклатуры.
  6. Посмотрите на свойства вновь созданного элемента формы. Платформа автоматически пропишет в свойстве «ПутьКДанным» значение Объект.Наименование.Цвет.

Преимущества данного метода: Программа работает моментально. При выборе номенклатуры на форме поле цвета будет автоматически и мгновенно обновляться силами самой платформы без единой строчки программного кода. При этом размер базы данных не увеличивается за счет хранения дублирующейся информации.

Важное архитектурное замечание: Реквизит или Характеристика?

В процессе обсуждения этой темы на форумах часто возникает важный методологический спор о том, как правильно проектировать структуру базы данных. Давайте выясним разницу между статическим реквизитом и характеристикой:

Применяйте описанные методики осознанно, учитывайте нагрузку на сервер и клиент-серверную архитектуру управляемых форм 1С, и ваши интерфейсы будут работать быстро и отзывчиво для пользователей!

← На главную