Работа с перечислениями в 1С 8.3: значения, запросы, формы и типичные ловушки
Содержание
К значению перечисления в 1С обращаются тремя способами, и выбор зависит от того, где выполняется код. На сервере пишут Перечисления.ВидыОплат.Наличные, в тексте запроса — ЗНАЧЕНИЕ(Перечисление.ВидыОплат.Наличные), а в клиентском модуле формы — ПредопределенноеЗначение("Перечисление.ВидыОплат.Наличные"). Если перепутать контекст, код не скомпилируется или упадёт при выполнении.
Это механизм платформы 8.3, а не конкретной конфигурации: в БП, ЗУП, УТ и самописных базах методы обращения к значениям одинаковы. Отличаются только имена самих перечислений.
Что такое перечисление в 1С и когда его выбирают
Перечисление — объект метаданных с фиксированным списком значений. Список задаёт разработчик в Конфигураторе, пользователь в режиме 1С:Предприятие его не меняет. Типичные примеры из типовых конфигураций: виды оплат, ставки НДС, статусы заказов, пол физлица.
Чем перечисление отличается от справочника:
- 🔒 Состав фиксирован. Новое значение появляется только после изменения конфигурации и обновления базы.
- 🧩 Нет реквизитов. У значения есть только имя, синоним и порядок. Хранить в нём ставку, счёт или цвет нельзя.
- ⚡ Лёгкий тип. В базе значение хранится как ссылка, но таблица перечисления крошечная, а сравнение в коде идёт без чтения данных.
- 🧭 Код опирается на значения. На перечислениях строят ветвления:
Если ВидОплаты = Перечисления.ВидыОплат.Наличные Тогда.
| Задача | Что взять |
|---|---|
| Набор вариантов, на которые завязана логика кода | Перечисление |
| Пользователь должен добавлять варианты сам | Справочник |
| Нужны реквизиты у варианта (процент, счёт, описание) | Справочник, при необходимости с предопределёнными элементами |
| Вариант из системного набора платформы (вид движения, режим записи) | Системное перечисление |
Системные перечисления — ВидДвиженияНакопления, РежимЗаписиДокумента, РежимПроведенияДокумента и подобные — встроены в платформу. К ним обращаются без префикса Перечисления: ВидДвиженияНакопления.Приход.
Способы обращения к перечислениям в коде 1С
Прямое обращение через менеджер
Глобальное свойство Перечисления возвращает менеджер всех перечислений конфигурации. Через точку указывают имя перечисления и имя значения:
ВидОплаты = Перечисления.ВидыОплат.Наличные;
Если Документ.ВидОплаты = Перечисления.ВидыОплат.Безналичные Тогда
// логика для безнала
КонецЕсли;
Пустое значение получают методом ПустаяСсылка():
Если Не ЗначениеЗаполнено(Объект.ВидОплаты) Тогда
Объект.ВидОплаты = Перечисления.ВидыОплат.Наличные;
КонецЕсли;
Объект.Статус = Перечисления.СтатусыЗаказов.ПустаяСсылка();
ЗначениеЗаполнено() для перечисления возвращает Ложь на пустой ссылке — проверять удобнее им, чем сравнением с ПустаяСсылка().
Обращение по имени в строке
Когда имя перечисления или значения приходит из настройки или файла обмена, используют индексатор менеджера:
ИмяПеречисления = "ВидыОплат";
ИмяЗначения = "Наличные";
Значение = Перечисления[ИмяПеречисления][ИмяЗначения];
Если имени нет в конфигурации, платформа выбросит исключение. Для данных извне оборачивайте обращение в Попытка … Исключение.
Через индекс значения
Менеджер конкретного перечисления умеет переводить значение в номер по порядку и обратно. Нумерация с нуля, в порядке, заданном в Конфигураторе:
Индекс = Перечисления.ВидыОплат.Индекс(Перечисления.ВидыОплат.Безналичные); // например, 1
Значение = Перечисления.ВидыОплат.Получить(0); // первое значение в списке
Индекс зависит от порядка значений в дереве метаданных. Разработчик передвинул значение — индексы поменялись. Не сохраняйте индекс в базе или файле как идентификатор значения.
Сравнение таблицы способов
| Способ | Где работает | Когда использовать | Риск |
|---|---|---|---|
Перечисления.Имя.Значение | Сервер, внешняя обработка на сервере | Обычный код модулей объектов и общих модулей | Нет на клиенте |
Перечисления["Имя"]["Значение"] | Сервер | Имя приходит строкой | Исключение при опечатке |
ЗНАЧЕНИЕ(Перечисление.Имя.Значение) | Текст запроса | Условия и ВЫБОР в запросах | Ошибка при разборе запроса, если имени нет |
ПредопределенноеЗначение("Перечисление.Имя.Значение") | Клиент и сервер | Клиентские процедуры формы | Опечатка всплывёт только при выполнении |
Получить(Индекс) | Сервер | Перебор по номеру | Индекс меняется при перестановке |
Имя, синоним и перебор всех значений
Синоним (представление)
Строка(Значение) возвращает представление — синоним значения, который видит пользователь, например «Наличные». Для пустой ссылки вернётся пустая строка.
Имя значения в метаданных
Имя («Наличные» без пробелов, как в Конфигураторе) берут через метаданные:
Значение = Объект.ВидОплаты;
МенеджерПеречисления = Перечисления.ВидыОплат;
Индекс = МенеджерПеречисления.Индекс(Значение);
ИмяЗначения = Метаданные.Перечисления.ВидыОплат.ЗначенияПеречисления[Индекс].Имя;
Короче и универсальнее — XMLСтрока(Значение). Для ссылки на значение перечисления она возвращает именно имя значения. Обратное преобразование:
ИмяЗначения = XMLСтрока(Объект.ВидОплаты); // "Наличные"
Значение = XMLЗначение(Тип("ПеречислениеСсылка.ВидыОплат"), ИмяЗначения);
Этой парой удобно пользоваться в обменах и при выгрузке в JSON: имя переживает перенос между базами, а внутренний идентификатор ссылки — не всегда.
Перебор всех значений
Менеджер перечисления — коллекция, по нему можно пройти циклом:
Для Каждого Значение Из Перечисления.ВидыОплат Цикл
Сообщить(Строка(Значение));
КонецЦикла;
Если вместе со значением нужны имя и синоним из метаданных, идите по метаданным:
МетаПеречисление = Метаданные.Перечисления.ВидыОплат;
Для Каждого МетаЗначение Из МетаПеречисление.ЗначенияПеречисления Цикл
Значение = Перечисления.ВидыОплат[МетаЗначение.Имя];
Сообщить(МетаЗначение.Имя + " — " + МетаЗначение.Синоним);
КонецЦикла;
Тип реквизита, в котором хранится значение, называется ПеречислениеСсылка.ВидыОплат. Проверка типа выглядит так: ТипЗнч(Значение) = Тип("ПеречислениеСсылка.ВидыОплат").
Перечисления в запросах
В тексте запроса нет глобального контекста, поэтому Перечисления.ВидыОплат.Наличные там не сработает. Есть два рабочих варианта.
Функция ЗНАЧЕНИЕ — значение подставляется прямо в текст:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Ссылка,
| Заказ.Сумма
|ИЗ
| Документ.ЗаказКлиента КАК Заказ
|ГДЕ
| Заказ.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Выполнен)";
Пустое значение в запросе — ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ПустаяСсылка).
Параметр — когда значение вычисляется в коде или их несколько:
Запрос.Текст = "... ГДЕ Заказ.Статус В (&Статусы)";
Статусы = Новый Массив;
Статусы.Добавить(Перечисления.СтатусыЗаказов.Выполнен);
Статусы.Добавить(Перечисления.СтатусыЗаказов.Закрыт);
Запрос.УстановитьПараметр("Статусы", Статусы);
К самому перечислению можно обратиться как к таблице. У неё два поля — Ссылка и Порядок:
"ВЫБРАТЬ
| ВидыОплат.Ссылка,
| ВидыОплат.Порядок
|ИЗ
| Перечисление.ВидыОплат КАК ВидыОплат
|УПОРЯДОЧИТЬ ПО
| ВидыОплат.Порядок"
Сортировка по полю типа перечисления идёт по порядку значений в конфигурации, а не по алфавиту синонимов. Нужен алфавит — сортируйте по ПРЕДСТАВЛЕНИЕ(Поле).
Перечисления в управляемых формах
Обращение на клиенте
В клиентском контексте менеджера Перечисления нет. Код &НаКлиенте с прямым обращением упадёт с ошибкой Переменная не определена (Перечисления). Решение — функция глобального контекста ПредопределенноеЗначение:
&НаКлиенте
Процедура ВидОплатыПриИзменении(Элемент)
Элементы.РасчетныйСчет.Видимость =
(Объект.ВидОплаты = ПредопределенноеЗначение("Перечисление.ВидыОплат.Безналичные"));
КонецПроцедуры
Функция доступна и на клиенте, и на сервере, поэтому ради одной проверки не нужно заводить отдельную процедуру &НаСервере.
Ограничить список значений в поле
Поле формы с типом перечисления показывает все значения. Чтобы оставить часть, заполните список выбора элемента при создании формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
СписокВыбора = Элементы.ВидОплаты.СписокВыбора;
СписокВыбора.Очистить();
СписокВыбора.Добавить(Перечисления.ВидыОплат.Наличные);
СписокВыбора.Добавить(Перечисления.ВидыОплат.Безналичные);
КонецПроцедуры
Список выбора ограничивает только интерфейс. Значение по-прежнему можно записать кодом или обработкой, поэтому проверку допустимости дублируйте в ОбработкаПроверкиЗаполнения модуля объекта.
Переключатель вместо выпадающего списка
Для 2–4 значений удобнее переключатель. В Конфигураторе у поля формы установите вид Поле переключателя — платформа сама выведет все значения перечисления кнопками. Для длинных перечислений оставляйте поле ввода с выпадающим списком.
Можно ли добавить или изменить значение перечисления программно
Нет. Состав значений — часть метаданных. В режиме 1С:Предприятие нет ни метода создания нового значения, ни объекта перечисления, который можно записать. Перечисления.ВидыОплат.СоздатьЭлемент() не существует.
Как добавить значение правильно:
- Откройте Конфигуратор, в дереве метаданных разверните
Перечисленияи выберите нужное. - Откройте его свойства, на вкладке
Данныедобавьте значение: имя и синоним. - Расставьте порядок кнопками перемещения — он определит сортировку и индексы.
- Выполните
Конфигурация → Обновить конфигурацию базы данных(F7).
Для типовой конфигурации на поддержке правка перечисления снимает объект с поддержки или требует включить возможность изменения. Это осложнит следующие обновления. Если значение нужно добавить в типовую базу, сначала оцените, нельзя ли решить задачу справочником или реквизитом в расширении.
Что происходит с данными при правке значений:
- ✏️ Переименовали значение — данные не теряются, ссылка остаётся прежней. Ломается код, где значение указано по старому имени.
- 🔀 Переставили порядок — меняются индексы и сортировка в отчётах и запросах.
- 🗑 Удалили значение — в документах и регистрах, где оно было записано, появится битая ссылка:
<Объект не найден>. Перед удалением значения найдите все места, где оно используется, и замените его.
Если пользователю действительно нужен расширяемый список — переделайте перечисление в справочник. Значения, на которые завязан код, сделайте предопределёнными элементами: к ним обращаются так же через точку, Справочники.ВидыОплат.Наличные.
Перечисления в больших базах: что влияет на скорость
Само перечисление не тормозит: таблица значений маленькая, сравнение ссылок дешёвое. Медленными бывают запросы и формы вокруг него.
- 📇 Индексируйте реквизит, если по нему отбирают. Статус документа, по которому строится список «Заказы к выполнению», стоит пометить свойством
Индексироватьв Конфигураторе. Без индекса СУБД просматривает всю таблицу документа. - 🔍 Фильтруйте по ссылке, а не по представлению. Условие
ГДЕ ПРЕДСТАВЛЕНИЕ(Заказ.Статус) = "Выполнен"не использует индекс и ломается при смене синонима. ПишитеЗаказ.Статус = ЗНАЧЕНИЕ(...). - 📦 Несколько значений — одним условием.
Статус В (&Статусы)лучше цепочкиИЛИ, особенно в динамических списках. - 🌐 Не дёргайте сервер ради сравнения. В клиентском коде формы используйте
ПредопределенноеЗначение, а не серверный вызов, который вернёт значение перечисления. - 🧮 Не перебирайте метаданные в цикле по строкам. Если для каждой из 10 000 строк вы ищете имя значения через
Метаданные…ЗначенияПеречисления, вынесите соответствие «значение → имя» в переменную до цикла.
Пример кеша имён перед большим циклом:
ИменаЗначений = Новый Соответствие;
Для Каждого МетаЗначение Из Метаданные.Перечисления.ВидыОплат.ЗначенияПеречисления Цикл
ИменаЗначений.Вставить(Перечисления.ВидыОплат[МетаЗначение.Имя], МетаЗначение.Имя);
КонецЦикла;
Для Каждого Строка Из ТаблицаДанных Цикл
Строка.ИмяВидаОплаты = ИменаЗначений[Строка.ВидОплаты];
КонецЦикла;
Практические примеры использования перечислений
Ветвление логики проведения
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Если ВидОплаты = Перечисления.ВидыОплат.Наличные Тогда
СформироватьДвиженияПоКассе();
ИначеЕсли ВидОплаты = Перечисления.ВидыОплат.Безналичные Тогда
СформироватьДвиженияПоБанку();
Иначе
Отказ = Истина;
Сообщить("Не указан вид оплаты");
КонецЕсли;
КонецПроцедуры
Ветка Иначе нужна обязательно: она ловит пустое значение и те значения, которые добавят в перечисление позже.
Расшифровка значения в запросе
"ВЫБРАТЬ
| Заказ.Ссылка,
| ВЫБОР
| КОГДА Заказ.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Выполнен)
| ТОГДА ""Готов""
| КОГДА Заказ.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.ПустаяСсылка)
| ТОГДА ""Не указан""
| ИНАЧЕ ПРЕДСТАВЛЕНИЕ(Заказ.Статус)
| КОНЕЦ КАК СтатусТекстом
|ИЗ
| Документ.ЗаказКлиента КАК Заказ"
Выгрузка в JSON и загрузка обратно
В файл пишите имя значения через XMLСтрока, при загрузке восстанавливайте через XMLЗначение. Синоним для этого не подходит: его могут перевести или поправить, и загрузка перестанет находить значение.
Поиск значения по синониму
Прямого метода нет, но задача решается перебором:
Функция ЗначениеПоСинониму(ИмяПеречисления, Синоним)
Для Каждого Значение Из Перечисления[ИмяПеречисления] Цикл
Если Строка(Значение) = Синоним Тогда
Возврат Значение;
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункции
Ошибки при работе с перечислениями и как их распознать
Ещё две ловушки, которые не дают явного сообщения:
- 🧷 Значение из чужого перечисления. Реквизит составного типа принимает значения нескольких перечислений.
Перечисления.ВидыОплат.НаличныеиПеречисления.СпособыРасчета.Наличные— разные ссылки, хотя синоним одинаковый. - 🕳 Пустая ссылка вместо Неопределено. У реквизита типа перечисления пустое значение —
ПустаяСсылка(), а неНеопределено. ПроверкаЕсли ВидОплаты = Неопределенодля такого реквизита не сработает, используйтеЗначениеЗаполнено().