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

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

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

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

Разбор базовой задачи и типичной ошибки

Представим ситуацию: на форме документа или справочника есть два реквизита: НаименованиеАктива и ВидАктива. Оба имеют тип ПеречислениеСсылка. Нам нужно, чтобы при выборе в поле "Наименование" значения "Нематериальные активы", поле "Вид" автоматически принимало значение "Внеоборотные".

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


&НаКлиенте
Процедура НаименованиеПриИзменении(Элемент)
    
    // ОШИБКА 1: Сравнение ссылки с текстовой строкой
    Если ЭтаФорма.Элементы.Наименование = "НематериальныеАктивы" Тогда
        
        // ОШИБКА 2: Попытка присвоить значение элементу формы, а не данным
        // ОШИБКА 3: Использование коллекции "Перечисления" на клиенте
        ЭтаФорма.Элементы.ВидАктива = Перечисления.ВидыАктивов.Внеоборотные;
        
    КонецЕсли
    
КонецПроцедуры

Проанализируем причины неудачи. Во-первых, элементы перечисления в 1С — это не строки, а ссылочные типы. Сравнивать их с текстом в кавычках нельзя. Во-вторых, коллекция Перечисления доступна только на стороне сервера. В-третьих, значения нужно присваивать реквизиту данных (например, Объект.ВидАктива), а не элементу управления на форме.

Правильная реализация через ПредопределенноеЗначение

Для решения задачи на клиенте (в процедуре ПриИзменении) необходимо использовать функцию ПредопределенноеЗначение. Эта функция позволяет получить ссылку на объект метаданных, не обращаясь к серверу в явном виде (точнее, платформа делает это максимально оптимизировано).

Разберем корректный код:


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

Обратите внимание на синтаксис: в функции ПредопределенноеЗначение тип указывается в единственном числе (Перечисление), а не во множественном, как мы привыкли писать на сервере.

Использование коллекции Соответствие для чистоты кода

Если вариантов выбора много, конструкция Если...ИначеЕсли превратит ваш программный код в трудночитаемое полотно. В таких случаях мы рекомендуем использовать объект Соответствие. Это позволит сделать логику более гибкой и масштабируемой.

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


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

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

Продвинутый подход: Регистры сведений

Прописывать жесткие связи между перечислениями прямо в коде (так называемый "хардкодинг") — это не всегда удачное решение. Если завтра логика учета изменится и "Запасы" нужно будет относить к другой категории, вам придется вносить изменения в конфигурацию и обновлять базу у всех пользователей.

Проанализируем более профессиональный метод: использование Регистра сведений. Мы можем создать непериодический регистр сведений СвязиТиповАктивов с двумя измерениями:

  1. Наименование (Тип: ПеречислениеСсылка.НаименованияАктивов)
  2. Вид (Тип: ПеречислениеСсылка.ВидыАктивов)

Теперь в коде нам достаточно просто прочитать значение из регистра:


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

Такой подход позволяет администратору системы менять логику связей "на лету" без привлечения программиста, просто редактируя записи в регистре.

Важные нюансы при работе с формой

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

Мы рассмотрели путь от простого исправления ошибок в коде до создания гибкой архитектуры на базе регистров сведений. Выбор конкретного метода зависит от масштаба вашей задачи и требований к гибкости системы.

← На главную