Работа с перечислениями в 1С 8.3: значения, запросы, формы и типичные ловушки

· 9 мин

Содержание

К значению перечисления в 1С обращаются тремя способами, и выбор зависит от того, где выполняется код. На сервере пишут Перечисления.ВидыОплат.Наличные, в тексте запроса — ЗНАЧЕНИЕ(Перечисление.ВидыОплат.Наличные), а в клиентском модуле формы — ПредопределенноеЗначение("Перечисление.ВидыОплат.Наличные"). Если перепутать контекст, код не скомпилируется или упадёт при выполнении.

Это механизм платформы 8.3, а не конкретной конфигурации: в БП, ЗУП, УТ и самописных базах методы обращения к значениям одинаковы. Отличаются только имена самих перечислений.

Что такое перечисление в 1С и когда его выбирают

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

Чем перечисление отличается от справочника:

  • 🔒 Состав фиксирован. Новое значение появляется только после изменения конфигурации и обновления базы.
  • 🧩 Нет реквизитов. У значения есть только имя, синоним и порядок. Хранить в нём ставку, счёт или цвет нельзя.
  • ⚡ Лёгкий тип. В базе значение хранится как ссылка, но таблица перечисления крошечная, а сравнение в коде идёт без чтения данных.
  • 🧭 Код опирается на значения. На перечислениях строят ветвления: Если ВидОплаты = Перечисления.ВидыОплат.Наличные Тогда.
ЗадачаЧто взять
Набор вариантов, на которые завязана логика кодаПеречисление
Пользователь должен добавлять варианты самСправочник
Нужны реквизиты у варианта (процент, счёт, описание)Справочник, при необходимости с предопределёнными элементами
Вариант из системного набора платформы (вид движения, режим записи)Системное перечисление

Системные перечисления — ВидДвиженияНакопления, РежимЗаписиДокумента, РежимПроведенияДокумента и подобные — встроены в платформу. К ним обращаются без префикса Перечисления: ВидДвиженияНакопления.Приход.

Способы обращения к перечислениям в коде 1С

Прямое обращение через менеджер

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

ВидОплаты = Перечисления.ВидыОплат.Наличные;

Если Документ.ВидОплаты = Перечисления.ВидыОплат.Безналичные Тогда
    // логика для безнала
КонецЕсли;

Пустое значение получают методом ПустаяСсылка():

Если Не ЗначениеЗаполнено(Объект.ВидОплаты) Тогда
    Объект.ВидОплаты = Перечисления.ВидыОплат.Наличные;
КонецЕсли;

Объект.Статус = Перечисления.СтатусыЗаказов.ПустаяСсылка();

ЗначениеЗаполнено() для перечисления возвращает Ложь на пустой ссылке — проверять удобнее им, чем сравнением с ПустаяСсылка().

Обращение по имени в строке

Когда имя перечисления или значения приходит из настройки или файла обмена, используют индексатор менеджера:

ИмяПеречисления = "ВидыОплат";
ИмяЗначения     = "Наличные";

Значение = Перечисления[ИмяПеречисления][ИмяЗначения];

Если имени нет в конфигурации, платформа выбросит исключение. Для данных извне оборачивайте обращение в Попытка … Исключение.

Через индекс значения

Менеджер конкретного перечисления умеет переводить значение в номер по порядку и обратно. Нумерация с нуля, в порядке, заданном в Конфигураторе:

Индекс   = Перечисления.ВидыОплат.Индекс(Перечисления.ВидыОплат.Безналичные); // например, 1
Значение = Перечисления.ВидыОплат.Получить(0); // первое значение в списке

Индекс зависит от порядка значений в дереве метаданных. Разработчик передвинул значение — индексы поменялись. Не сохраняйте индекс в базе или файле как идентификатор значения.

Сравнение таблицы способов

СпособГде работаетКогда использоватьРиск
Перечисления.Имя.ЗначениеСервер, внешняя обработка на сервереОбычный код модулей объектов и общих модулейНет на клиенте
Перечисления["Имя"]["Значение"]СерверИмя приходит строкойИсключение при опечатке
ЗНАЧЕНИЕ(Перечисление.Имя.Значение)Текст запросаУсловия и ВЫБОР в запросахОшибка при разборе запроса, если имени нет
ПредопределенноеЗначение("Перечисление.Имя.Значение")Клиент и серверКлиентские процедуры формыОпечатка всплывёт только при выполнении
Получить(Индекс)СерверПеребор по номеруИндекс меняется при перестановке

Имя, синоним и перебор всех значений

Синоним (представление)

Строка(Значение) возвращает представление — синоним значения, который видит пользователь, например «Наличные». Для пустой ссылки вернётся пустая строка.

Имя значения в метаданных

Имя («Наличные» без пробелов, как в Конфигураторе) берут через метаданные:

Значение = Объект.ВидОплаты;
МенеджерПеречисления = Перечисления.ВидыОплат;

Индекс = МенеджерПеречисления.Индекс(Значение);
ИмяЗначения = Метаданные.Перечисления.ВидыОплат.ЗначенияПеречисления[Индекс].Имя;

Короче и универсальнее — XMLСтрока(Значение). Для ссылки на значение перечисления она возвращает именно имя значения. Обратное преобразование:

ИмяЗначения = XMLСтрока(Объект.ВидОплаты); // "Наличные"
Значение = XMLЗначение(Тип("ПеречислениеСсылка.ВидыОплат"), ИмяЗначения);

Этой парой удобно пользоваться в обменах и при выгрузке в JSON: имя переживает перенос между базами, а внутренний идентификатор ссылки — не всегда.

Перебор всех значений

Менеджер перечисления — коллекция, по нему можно пройти циклом:

Для Каждого Значение Из Перечисления.ВидыОплат Цикл
    Сообщить(Строка(Значение));
КонецЦикла;

Если вместе со значением нужны имя и синоним из метаданных, идите по метаданным:

МетаПеречисление = Метаданные.Перечисления.ВидыОплат;
Для Каждого МетаЗначение Из МетаПеречисление.ЗначенияПеречисления Цикл
    Значение = Перечисления.ВидыОплат[МетаЗначение.Имя];
    Сообщить(МетаЗначение.Имя + " — " + МетаЗначение.Синоним);
КонецЦикла;

Тип реквизита, в котором хранится значение, называется ПеречислениеСсылка.ВидыОплат. Проверка типа выглядит так: ТипЗнч(Значение) = Тип("ПеречислениеСсылка.ВидыОплат").

Перечисления в запросах

В тексте запроса нет глобального контекста, поэтому Перечисления.ВидыОплат.Наличные там не сработает. Есть два рабочих варианта.

Функция ЗНАЧЕНИЕ — значение подставляется прямо в текст:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    Заказ.Ссылка,
|    Заказ.Сумма
|ИЗ
|    Документ.ЗаказКлиента КАК Заказ
|ГДЕ
|    Заказ.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Выполнен)";

Пустое значение в запросе — ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ПустаяСсылка).

Параметр — когда значение вычисляется в коде или их несколько:

Запрос.Текст = "... ГДЕ Заказ.Статус В (&Статусы)";

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

К самому перечислению можно обратиться как к таблице. У неё два поля — Ссылка и Порядок:

"ВЫБРАТЬ
|    ВидыОплат.Ссылка,
|    ВидыОплат.Порядок
|ИЗ
|    Перечисление.ВидыОплат КАК ВидыОплат
|УПОРЯДОЧИТЬ ПО
|    ВидыОплат.Порядок"

Сортировка по полю типа перечисления идёт по порядку значений в конфигурации, а не по алфавиту синонимов. Нужен алфавит — сортируйте по ПРЕДСТАВЛЕНИЕ(Поле).

Перечисления в управляемых формах

Обращение на клиенте

В клиентском контексте менеджера Перечисления нет. Код &НаКлиенте с прямым обращением упадёт с ошибкой Переменная не определена (Перечисления). Решение — функция глобального контекста ПредопределенноеЗначение:

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

Функция доступна и на клиенте, и на сервере, поэтому ради одной проверки не нужно заводить отдельную процедуру &НаСервере.

Ограничить список значений в поле

Поле формы с типом перечисления показывает все значения. Чтобы оставить часть, заполните список выбора элемента при создании формы:

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

Список выбора ограничивает только интерфейс. Значение по-прежнему можно записать кодом или обработкой, поэтому проверку допустимости дублируйте в ОбработкаПроверкиЗаполнения модуля объекта.

Переключатель вместо выпадающего списка

Для 2–4 значений удобнее переключатель. В Конфигураторе у поля формы установите вид Поле переключателя — платформа сама выведет все значения перечисления кнопками. Для длинных перечислений оставляйте поле ввода с выпадающим списком.

Можно ли добавить или изменить значение перечисления программно

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

Как добавить значение правильно:

  1. Откройте Конфигуратор, в дереве метаданных разверните Перечисления и выберите нужное.
  2. Откройте его свойства, на вкладке Данные добавьте значение: имя и синоним.
  3. Расставьте порядок кнопками перемещения — он определит сортировку и индексы.
  4. Выполните Конфигурация → Обновить конфигурацию базы данных (F7).

Для типовой конфигурации на поддержке правка перечисления снимает объект с поддержки или требует включить возможность изменения. Это осложнит следующие обновления. Если значение нужно добавить в типовую базу, сначала оцените, нельзя ли решить задачу справочником или реквизитом в расширении.

Что происходит с данными при правке значений:

  • ✏️ Переименовали значение — данные не теряются, ссылка остаётся прежней. Ломается код, где значение указано по старому имени.
  • 🔀 Переставили порядок — меняются индексы и сортировка в отчётах и запросах.
  • 🗑 Удалили значение — в документах и регистрах, где оно было записано, появится битая ссылка: <Объект не найден>. Перед удалением значения найдите все места, где оно используется, и замените его.

Если пользователю действительно нужен расширяемый список — переделайте перечисление в справочник. Значения, на которые завязан код, сделайте предопределёнными элементами: к ним обращаются так же через точку, Справочники.ВидыОплат.Наличные.

Перечисления в больших базах: что влияет на скорость

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

  • 📇 Индексируйте реквизит, если по нему отбирают. Статус документа, по которому строится список «Заказы к выполнению», стоит пометить свойством Индексировать в Конфигураторе. Без индекса СУБД просматривает всю таблицу документа.
  • 🔍 Фильтруйте по ссылке, а не по представлению. Условие ГДЕ ПРЕДСТАВЛЕНИЕ(Заказ.Статус) = "Выполнен" не использует индекс и ломается при смене синонима. Пишите Заказ.Статус = ЗНАЧЕНИЕ(...).
  • 📦 Несколько значений — одним условием. Статус В (&Статусы) лучше цепочки ИЛИ, особенно в динамических списках.
  • 🌐 Не дёргайте сервер ради сравнения. В клиентском коде формы используйте ПредопределенноеЗначение, а не серверный вызов, который вернёт значение перечисления.
  • 🧮 Не перебирайте метаданные в цикле по строкам. Если для каждой из 10 000 строк вы ищете имя значения через Метаданные…ЗначенияПеречисления, вынесите соответствие «значение → имя» в переменную до цикла.

Пример кеша имён перед большим циклом:

ИменаЗначений = Новый Соответствие;
Для Каждого МетаЗначение Из Метаданные.Перечисления.ВидыОплат.ЗначенияПеречисления Цикл
    ИменаЗначений.Вставить(Перечисления.ВидыОплат[МетаЗначение.Имя], МетаЗначение.Имя);
КонецЦикла;

Для Каждого Строка Из ТаблицаДанных Цикл
    Строка.ИмяВидаОплаты = ИменаЗначений[Строка.ВидОплаты];
КонецЦикла;

Практические примеры использования перечислений

Ветвление логики проведения

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

Ветка Иначе нужна обязательно: она ловит пустое значение и те значения, которые добавят в перечисление позже.

Расшифровка значения в запросе

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

Выгрузка в JSON и загрузка обратно

В файл пишите имя значения через XMLСтрока, при загрузке восстанавливайте через XMLЗначение. Синоним для этого не подходит: его могут перевести или поправить, и загрузка перестанет находить значение.

Поиск значения по синониму

Прямого метода нет, но задача решается перебором:

Функция ЗначениеПоСинониму(ИмяПеречисления, Синоним)
    Для Каждого Значение Из Перечисления[ИмяПеречисления] Цикл
        Если Строка(Значение) = Синоним Тогда
            Возврат Значение;
        КонецЕсли;
    КонецЦикла;
    Возврат Неопределено;
КонецФункции

Ошибки при работе с перечислениями и как их распознать

Диагностика: выберите симптом

Ещё две ловушки, которые не дают явного сообщения:

  • 🧷 Значение из чужого перечисления. Реквизит составного типа принимает значения нескольких перечислений. Перечисления.ВидыОплат.Наличные и Перечисления.СпособыРасчета.Наличные — разные ссылки, хотя синоним одинаковый.
  • 🕳 Пустая ссылка вместо Неопределено. У реквизита типа перечисления пустое значение — ПустаяСсылка(), а не Неопределено. Проверка Если ВидОплаты = Неопределено для такого реквизита не сработает, используйте ЗначениеЗаполнено().

Частые вопросы

Чем перечисление отличается от предопределённых элементов справочника?
Предопределённые элементы живут в справочнике: у них есть реквизиты, а пользователь может добавлять обычные элементы рядом. Перечисление — только фиксированный набор значений без реквизитов.
Можно ли перевести синонимы значений на другой язык?
Да. Синоним — многоязычная строка, перевод задают в свойствах значения в Конфигураторе. Имя значения при этом не меняется, поэтому код и обмены продолжают работать.
Как вывести значения перечисления в макет печатной формы?
Передайте в параметр макета само значение или Строка(Значение). Табличный документ выведет синоним.
Сколько значений может быть в перечислении?
Жёсткого предела, с которым сталкиваются на практике, нет. Но если значений десятки и их список регулярно правят, это сигнал перейти на справочник.
Можно ли сделать реквизит обязательным, если это перечисление?
Да. Свойство «Проверка заполнения» со значением «Выдавать ошибку» не даст записать объект с пустой ссылкой, так же как для реквизитов других ссылочных типов.