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

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

При разработке конфигураций на платформе 1С:Предприятие 8.3 часто возникает задача, когда при выборе одного значения в документе необходимо автоматически заполнить другие поля, основываясь на данных, которые хранятся «внутри» выбранного объекта. В нашем примере мы рассмотрим ситуацию с билетной кассой: когда пользователь выбирает КатегорияБилета, система должна проверить внутреннее свойство этой категории (ТипБилета) и, если это «Входной билет», автоматически установить значение в поле Экскурсовод.

Рассмотрим пошагово, как правильно реализовать эту логику, соблюдая принципы клиент-серверной разработки и стандарты программирования 1С.

Понимание клиент-серверного взаимодействия

Прежде чем приступать к написанию кода, разберем важный теоретический аспект. В управляемом приложении 1С код разделен на Клиент (то, что видит пользователь) и Сервер (где происходят основные расчеты и работа с базой данных). Когда вы выбираете ссылку на элемент справочника в поле документа на клиенте, программа «знает» только саму ссылку и ее наименование. Если вам нужно заглянуть «внутрь» этого справочника и узнать значение его реквизитов (например, ТипБилета), вам необходимо обратиться к серверу.

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

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

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

Рассмотрим структуру получившегося кода:


&НаКлиенте
Процедура тит_БилетыКатегорияБилетаПриИзменении(Элемент)
    // Получаем текущую строку табличной части
    ТекущаяСтрока = Элементы.тит_Билеты.ТекущиеДанные;
    
    Если ТекущаяСтрока <> Неопределено Тогда
        // Вызываем серверную процедуру для получения данных из БД
        ОбработатьИзменениеКатегорииНаСервере(ТекущаяСтрока.НомерСтроки);
    КонецЕсли;
КонецПроцедуры

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

Теперь проанализируем ситуацию на сервере. Нам нужно получить данные из справочника и сравнить их со значением из Перечисления. Обратите внимание, что обращение к перечислениям в коде всегда выполняется через объект Перечисления.


&НаСервере
Процедура ОбработатьИзменениеКатегорииНаСервере(НомерСтроки)
    // Находим нужную строку в данных объекта
    // Индексация в коллекции начинается с 0, поэтому вычитаем 1
    СтрокаДокумента = Объект.тит_Билеты[НомерСтроки - 1];
    
    // Проверяем, заполнена ли категория, чтобы избежать ошибок
    Если ЗначениеЗаполнено(СтрокаДокумента.КатегорияБилета) Тогда
        
        // Вот оно — обращение к реквизиту реквизита через точку!
        // Программа «пробрасывает» неявный запрос к базе данных
        Если СтрокаДокумента.КатегорияБилета.ТипБилета = Перечисления.тит_ТипБилета.ВходнойБилет Тогда
            
            // Устанавливаем значение экскурсовода
            СтрокаДокумента.Экскурсовод = Справочники.тит_Экскурсоводы.БезЭкскурсовода;
            
        КонецЕсли;
        
    КонецЕсли;
КонецПроцедуры

Важный нюанс: Использование предопределенных элементов

В процессе обсуждения на форуме прозвучала важная мысль: как правильно подставлять значение «Без экскурсовода»? Рассмотрим два подхода:

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

Оптимизация производительности (разыменование ссылок)

Выясним причину, почему опытные разработчики предостерегают от частого использования «точек» в коде. Обращение типа СтрокаДокумента.КатегорияБилета.ТипБилета порождает так называемый «неявный запрос». Платформа вынуждена выполнить SELECT ко всей таблице справочника, чтобы достать одно значение.

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


// Пример получения данных через запрос (более производительно)
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Категории.ТипБилета КАК Тип
    |ИЗ
    |	Справочник.тит_КатегорияБилета КАК Категории
    |ГДЕ
    |	Категории.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", СтрокаДокумента.КатегорияБилета);
Результат = Запрос.Выполнить().Выбрать();

Если Результат.Следующий() Тогда
    // Работаем с результатом
КонецЕсли;

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

Иногда задачу можно решить даже без программирования. Если ваша цель — сделать так, чтобы при определенном типе билета в списке экскурсоводов был доступен только вариант «Без экскурсовода», рассмотрите использование Связей параметров выбора в свойствах реквизита.

Однако для автоматической подстановки (заполнения поля без участия пользователя) программный метод через событие ПриИзменении, который мы разобрали выше, является единственным верным решением.

Резюме для разработчика

Подведем итог нашему анализу ситуации:

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

← На главную