Часто перед начинающими разработчиками 1С встает задача: в зависимости от определенных условий изменить реквизит документа. Сложность возникает, когда этот реквизит имеет ссылочный тип, например, «Статус заказа», который ссылается на справочник «Статусы заказов». Простое присвоение текстового значения, как СтатусЗаказа = "Черновик";, приведет к ошибке, так как система ожидает не строку, а ссылку на конкретный элемент справочника.
Давайте подробно разберем, как правильно решить эту задачу на примере, и проанализируем лучшие практики, которые сделают ваш код надежным и понятным.
Рассмотрим типовую ситуацию: есть документ «Заказ клиента». При его создании ему должен автоматически присваиваться статус «Черновик». А при попытке установить статус «Согласован клиентом», система должна проверить, заполнены ли поля «Клиент», «Номенклатура» и «Количество».
Прежде всего, выясним причину проблемы. В 1С существует строгая типизация данных. Если реквизит СтатусЗаказа имеет тип СправочникСсылка.СтатусыЗаказов, это означает, что его значением может быть только уникальная ссылка на один из элементов, хранящихся в справочнике «СтатусыЗаказов». Строка, например, "Черновик", является лишь наименованием одного из этих элементов, но не самой ссылкой. Система не знает, какому именно элементу соответствует эта строка, поэтому попытка присвоения вызовет ошибку.
Для работы со значениями, которые являются константами в логике программы (статусы, виды операций, предопределенные контрагенты и т.д.), в 1С существует специальный механизм — предопределенные элементы. Это такие же элементы справочника, но у них есть уникальное системное имя, к которому можно обращаться напрямую из кода.
Преимущества:
Разберем по шагам, как создать и использовать предопределенный элемент.
Справочники.СтатусыЗаказов.
Черновик.Теперь, когда предопределенный элемент создан, вы можете легко обратиться к нему в коде. Ваш код для присвоения статуса будет выглядеть так:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Пример простого присвоения статуса "Черновик"
СтатусЗаказа = Справочники.СтатусыЗаказов.Черновик;
КонецПроцедуры
Обратите внимание: мы обращаемся через точку Справочники.ИмяСправочника.ИмяПредопределенногоЭлемента. Именно `Имя`, которое вы указали в конфигураторе, используется здесь.
Что делать при ошибке «Поле объекта не обнаружено»?
Эта ошибка — частый спутник новичков при работе с предопределенными элементами. Она означает, что система не может найти предопределенный элемент с указанным именем. Возможные причины:
ЧерновикСтатус, а в конфигураторе — Черновик).Если набор статусов жестко фиксирован, не должен меняться пользователями и определяется только на уровне разработки, то более правильным решением будет использование объекта Перечисление.
В этом случае вы создаете не справочник, а объект `Перечисление` (например, `СтатусыЗаказов`) и добавляете в него все возможные значения (`Черновик`, `СогласованКлиентом`, `Отгружен`). Реквизит документа `СтатусЗаказа` будет иметь тип `ПеречислениеСсылка.СтатусыЗаказов`.
Код присвоения будет очень похож:
// Для реквизита с типом Перечисление
СтатусЗаказа = Перечисления.СтатусыЗаказов.Черновик;
Выбор между справочником с предопределенными элементами и перечислением зависит от задачи. Если пользователи должны иметь возможность добавлять новые статусы — используйте справочник. Если нет — перечисление.
Существует еще один способ получить ссылку на элемент — найти его по наименованию. Этот метод стоит использовать только в крайних случаях, так как он очень ненадежен.
// Этот код сработает, но он хрупкий
СтатусЗаказа = Справочники.СтатусыЗаказов.НайтиПоНаименованию("Черновик");
Почему этот способ плох? Главный недостаток в том, что он завязан на данные, которые может изменить пользователь. Если администратор или менеджер решит переименовать статус «Черновик» в «Проект», ваш код перестанет работать, и найти причину ошибки будет непросто. Используйте этот метод, только если у вас нет возможности изменить конфигурацию и добавить предопределенные элементы.
Теперь давайте соберем все вместе и напишем полный код для обработчика события ПередЗаписью в модуле объекта документа «Заказ клиента», который реализует все первоначальные требования.
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// 1. Устанавливаем статус "Черновик" для нового документа по умолчанию.
// Функция ЭтоНовый() возвращает Истина, если документ создается впервые.
Если ЭтоНовый() Тогда
СтатусЗаказа = Справочники.СтатусыЗаказов.Черновик;
КонецЕсли;
// 2. Проверяем условия для статуса "Согласован клиентом".
// Обращаемся к предопределенному элементу "СогласованКлиентом".
Если СтатусЗаказа = Справочники.СтатусыЗаказов.СогласованКлиентом Тогда
ПеременнаяДляСообщений = ""; // Будем собирать все ошибки в одну строку
// Проверяем, заполнена ли информация о клиенте
Если НЕ ЗначениеЗаполнено(КлиентЗаказчик) Тогда
ПеременнаяДляСообщений = ПеременнаяДляСообщений + "Не указан клиент! ";
КонецЕсли;
// Предположим, что товары находятся в табличной части "Товары"
// Проверяем, что в заказе есть хотя бы одна строка с лесопродукцией
Если Товары.Количество() = 0 Тогда
ПеременнаяДляСообщений = ПеременнаяДляСообщений + "Не указана лесопродукция! ";
Иначе
// Дополнительно можно проверить количество в каждой строке
Для Каждого Стр Из Товары Цикл
Если Стр.Количество <= 0 Тогда
ПеременнаяДляСообщений = ПеременнаяДляСообщений + "В строке " + Стр.НомерСтроки + " указано некорректное количество! ";
КонецЕсли;
КонецЦикла;
КонецЕсли;
// 3. Если были ошибки, сообщаем пользователю и отменяем запись.
Если НЕ ПустаяСтрока(ПеременнаяДляСообщений) Тогда
// Выводим сообщение пользователю
Сообщить("Заказ не может быть согласован: " + ПеременнаяДляСообщений);
// Отменяем запись документа. Объект не будет сохранен в базу.
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Подведем итог. Для работы с постоянными, ключевыми для логики программы значениями (статусы, типы, виды) всегда используйте предопределенные элементы справочников или перечисления. Это стандарт разработки на платформе 1С, который делает ваш код надежным, читаемым и устойчивым к изменениям, вносимым пользователями.