К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как проверить, есть ли реквизит в документе 1С

Способы проверить наличие реквизита в документе 1С: через метаданные, конфигуратор, отладчик и функцию ЕстьРеквизит. Примеры кода и типичные ошибки.

Задача проверить наличие реквизита у документа возникает в двух ситуациях: когда вы пишете универсальный код, который должен работать с разными видами документов, и когда нужно убедиться, что в конфигурации вообще существует нужное поле перед обращением к нему. Прямое обращение к несуществующему реквизиту вызывает ошибку «Поле объекта не обнаружено», поэтому в обменных механизмах, универсальных обработках и коде для нескольких конфигураций проверка обязательна.

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

Проверка через метаданные в коде

Основной способ — обратиться к коллекции реквизитов через объект метаданных. У каждого объекта документа есть метод Метаданные(), который возвращает описание структуры, а у него — коллекцию Реквизиты с методом Найти(). Если реквизит найден, метод вернёт объект описания, если нет — значение Неопределено.

Типовой фрагмент кода выглядит так:

Функция ЕстьРеквизитДокумента(ДокументОбъект, ИмяРеквизита)

МетаданныеДокумента = ДокументОбъект.Метаданные();

Возврат МетаданныеДокумента.Реквизиты.Найти(ИмяРеквизита) <> Неопределено;

КонецФункции

Использование: Если ЕстьРеквизитДокумента(ДокОбъект, "Соглашение") Тогда .... Такой подход работает и на сервере, и на толстом клиенте, и не зависит от того, какая конфигурация развёрнута — код универсален.

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

Проверка стандартных реквизитов и реквизитов табличных частей

Если нужно проверить стандартный реквизит (например, «Организация» иногда выносится в шапку как обычный, а иногда его нет вовсе — но Номер и Дата есть всегда), используйте коллекцию СтандартныеРеквизиты:

Если МетаданныеДокумента.СтандартныеРеквизиты.Найти("Номер") <> Неопределено Тогда

// реквизит есть

КонецЕсли;

Для реквизитов табличной части сначала проверяется наличие самой табличной части, затем — реквизита внутри неё:

ТабЧасть = МетаданныеДокумента.ТабличныеЧасти.Найти("Товары");

Если ТабЧасть <> Неопределено

И ТабЧасть.Реквизиты.Найти("СтавкаНДС") <> Неопределено Тогда

// реквизит табличной части существует

КонецЕсли;

Пропуск проверки существования табличной части — частая причина ошибки: если табличной части «Товары» в документе нет, обращение к её реквизитам вернёт Неопределено, и следующая попытка вызвать у него метод приведёт к падению кода.

Функция ЕстьРеквизитОбъекта из БСП

В типовых конфигурациях на базе библиотеки стандартных подсистем (УТ, ERP, Бухгалтерия, ЗУП) уже есть готовая функция ОбщегоНазначения.ЕстьРеквизитОбъекта(ИмяРеквизита, МетаданныеОбъекта). Она проверяет и обычные, и стандартные реквизиты, и реквизиты, доступные через точку от стандартных (например, «Ссылка.Организация»).

Если ОбщегоНазначения.ЕстьРеквизитОбъекта("Комментарий", ДокументОбъект.Метаданные()) Тогда

Комментарий = ДокументОбъект.Комментарий;

КонецЕсли;

Преимущество функции БСП — она уже протестирована и учитывает нюансы платформы. Ограничение: она доступна только в конфигурациях, где внедрена БСП. В самописных конфигурациях без библиотеки придётся использовать собственную функцию через метаданные, как показано выше.

Сравнение вариантов

Своя функция через Метаданные().Реквизиты.Найти()

Работает в любой конфигурации, включая самописные. Нужно отдельно проверять стандартные реквизиты и табличные части.

ОбщегоНазначения.ЕстьРеквизитОбъекта (БСП)

Готовое решение в типовых конфигурациях, учитывает все виды реквизитов. Недоступно без внедрённой БСП.

Попытка обращения через Попытка/Исключение

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

Визуальная проверка в конфигураторе

Если нужно просто узнать, есть ли реквизит у конкретного вида документов, откройте конфигуратор и найдите документ в дереве конфигурации (ветка «Документы»). Разверните узел документа — реквизиты шапки находятся в ветке «Реквизиты», табличные части — в ветке «Табличные части», у каждой из которых есть своя подветка реквизитов.

Быстрее воспользоваться поиском: Ctrl+Shift+F, поиск по метаданным, или кнопка «Найти» в дереве конфигурации. Также удобна глобальная проверка через пункт «Конфигурация — Поиск ссылок в объектах», если нужно понять, где реквизит используется.

Дополнительно наличие реквизита видно в форме документа в режиме предприятия: откройте документ и проверьте, выведено ли поле. Но учтите — реквизит может существовать в объекте, но не быть выведенным на форму, поэтому отсутствие поля на экране не означает отсутствие реквизита в метаданных.

Порядок действий в конфигураторе
  1. 1
    Откройте конфигуратор и дерево конфигурации
  2. 2
    Разверните ветку «Документы» и найдите нужный вид документа
  3. 3
    Разверните узел документа и посмотрите ветку «Реквизиты»
  4. 4
    Для табличных частей разверните «Табличные части» и ветку нужной части
  5. 5
    Если реквизита нет в списке — его не существует в метаданных этого документа

Проверка через отладчик и вычисление выражений

В режиме отладки можно проверить наличие реквизита без изменения кода. Установите точку останова там, где доступна переменная с документом, запустите отладку и в окне «Вычислить выражение» (Shift+F9) введите:

ДокументОбъект.Метаданные().Реквизиты.Найти("ИмяРеквизита")

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

Также в табло можно вывести всю коллекцию реквизитов и просмотреть её как список — так видны сразу все реквизиты объекта с их типами.

Типичные ошибки и ограничения

Типичные ошибки
01
Поиск реквизита табличной части в коллекции Реквизиты документа — такие реквизиты лежат внутри описания табличной части, и поиск в шапке всегда вернёт Неопределено
02
Проверка только обычных реквизитов при поиске стандартных — Номер и Дата находятся в СтандартныеРеквизиты
03
Использование Попытка/Исключение вместо проверки метаданных — код работает медленнее и маскирует реальные ошибки
04
Обращение к свойству ссылки вместо объекта — у объекта типа ДокументСсылка нет значений реквизитов напрямую, но метод Метаданные() у ссылки доступен
05
Неучтённый регистр имени — встроенный язык 1С нечувствителен к регистру, но опечатка в имени реквизита вернёт Неопределено без какой-либо ошибки

Отдельно стоит сказать о динамических реквизитах. Если реквизит добавлен не в конфигураторе, а через механизм дополнительных реквизитов и сведений (в типовых конфигурациях), то в метаданных его не будет — он хранится в табличной части «ДополнительныеРеквизиты» и в справочнике наборов свойств. Проверять такие реквизиты нужно поиском по свойству в этой табличной части, а не через метаданные.

Ещё одно ограничение: проверка через метаданные показывает структуру конфигурации, а не заполненность. Реквизит может существовать, но быть пустым у конкретного документа — для проверки заполненности используйте ЗначениеЗаполнено() после того, как убедились, что реквизит есть.

Контрольные точки

Как проверить результат

Результат Найти()
Норма

Возвращён объект описания реквизита — можно обращаться к реквизиту в коде

Тревожный признак

Возвращено Неопределено — реквизита нет, обращение вызовет ошибку

Реквизит дополнительный (через свойства)
Норма

Найден в табличной части ДополнительныеРеквизиты по ссылке на свойство

Тревожный признак

Поиск через метаданные — такой реквизит там не отображается

Работа кода в разных документах
Норма

Универсальная функция корректно возвращает Истина/Ложь для всех видов документов

Тревожный признак

Код падает с ошибкой «Поле объекта не обнаружено» на отдельных видах документов

Когда проверка особенно нужна

Проверка наличия реквизита критична в универсальных обработках: обменах данными между разными конфигурациями, обработках группового изменения реквизитов, внешних печатных формах, которые подключаются к разным видам документов. В этих случаях код не знает заранее структуру объекта и обязан проверять её перед обращением.

В коде, жёстко привязанном к одной конфигурации и одному виду документа, проверка обычно избыточна — структура известна на этапе разработки. Но она становится полезной при обновлении типовых конфигураций: если реквизит мог быть удалён или переименован поставщиком, проверка позволит коду доработанного модуля не упасть, а корректно обработать ситуацию.

Итог

Что важно запомнить

Наличие реквизита проверяется через Метаданные().Реквизиты.Найти(Имя) — Неопределено означает отсутствие. Стандартные реквизиты ищутся в СтандартныеРеквизиты, реквизиты табличных частей — внутри описания табличной части. В типовых конфигурациях используйте ОбщегоНазначения.ЕстьРеквизитОбъекта. Дополнительные реквизиты через механизм свойств в метаданных не видны и проверяются отдельно.

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

Как проверить наличие реквизита у ссылки на документ, не получая объект?

Метод Метаданные() доступен и у ссылки: ДокументСсылка.Метаданные().Реквизиты.Найти("Имя"). Получать объект через ПолучитьОбъект() для проверки не нужно — это лишнее обращение к базе данных.

Почему Найти() возвращает Неопределено, хотя реквизит точно есть?

Чаще всего реквизит является стандартным (ищите в СтандартныеРеквизиты), принадлежит табличной части (ищите внутри неё) или добавлен как дополнительный через механизм свойств — в метаданных его нет. Также проверьте опечатки в имени.

Можно ли проверить реквизит через Попытка/Исключение?

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

Как проверить реквизит в запросе?

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

Как узнать тип реквизита, если он найден?

Объект описания реквизита, возвращаемый методом Найти(), содержит свойство Тип — это описание типов. Через него можно проверить, содержит ли реквизит нужный тип: Реквизит.Тип.СодержитТип(Тип("СправочникСсылка.Контрагенты")).

Работает ли проверка на управляемых формах и тонком клиенте?

Коллекции метаданных доступны на сервере. На тонком клиенте вызов Метаданные() у объекта недоступен, поэтому проверку выполняйте в серверной процедуре модуля объекта, менеджера документа или общего модуля с флагом «Сервер».