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

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

1С: проверка, что значение является документом

Проверка в 1С, что значение является документом: ТипЗнч, Метаданные, отличие ссылки от объекта, примеры кода для сервера и клиента.

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

Главная сложность в том, что «документ» в 1С — это не один тип, а целое семейство: для каждого вида документа существуют отдельные типы ДокументСсылка и ДокументОбъект, а также выборка, список и менеджер. Поэтому простое сравнение типа с конкретным значением подходит только для частных случаев, а для универсальной проверки нужны другие приёмы.

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

Что именно нужно проверить: ссылка, объект или тип в целом

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

Если значение пришло из реквизита другого объекта, из параметра запроса или из поля формы — это почти всегда ссылка. Если значение создано методом ПолучитьОбъект() или пришло в обработчик ПередЗаписью в виде Источник — это объект. Универсальная проверка «это документ вообще» должна корректно срабатывать для обоих вариантов.

Проверка на конкретный вид документа через ТипЗнч

Когда заранее известно, какой вид документа ожидается, используется функция ТипЗнч() в сочетании с функцией Тип(), где имя типа задаётся строкой:

Если ТипЗнч(Значение) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда

// Значение — ссылка на реализацию

КонецЕсли;

Для объекта документа строка будет другой: Тип("ДокументОбъект.РеализацияТоваровУслуг"). Это важно: проверка на ссылку не сработает для объекта и наоборот, поэтому при необходимости проверяйте оба варианта через Или.

Ограничение способа: имя вида документа жёстко зашито в коде. Если документ переименуют в конфигураторе, строка станет невалидной и вызовет ошибку при выполнении. Для типовых конфигураций с регулярными обновлениями надёжнее проверка через метаданные, либо функции из общих модулей типа «ОбщегоНазначения», если они есть в вашей конфигурации.

Универсальная проверка «это документ» через метаданные

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

Функция ЭтоДокумент(Значение) Экспорт

МетаданныеЗначения = Значение.Метаданные();

Возврат Метаданные.Документы.Содержит(МетаданныеЗначения);

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

Метод Метаданные() доступен и у ссылки, и у объекта, поэтому функция работает универсально. Аналогично проверяются другие классы: Метаданные.Справочники, Метаданные.ПланыСчетов и так далее.

Альтернатива — определить тип документа по строковому представлению типа. Функция XMLТипЗнч(Значение) или преобразование типа в строку дают имя вида ДокументСсылка.ИмяДокумента, откуда можно извлечь имя вида. Этот приём медленнее и менее читаем, поэтому применяйте его только там, где метаданные недоступны.

Порядок действий для универсальной проверки
  1. 1
    Убедитесь, что проверяемое значение не Неопределено и не NULL — иначе обращение к Метаданные() вызовет ошибку.
  2. 2
    Получите метаданные значения: МетаданныеЗначения = Значение.Метаданные().
  3. 3
    Проверьте принадлежность: Метаданные.Документы.Содержит(МетаданныеЗначения).
  4. 4
    Если нужен конкретный вид — сравните МетаданныеЗначения.Имя с ожидаемым именем документа.
  5. 5
    Проверьте результат на реальных данных: передайте в функцию ссылку, объект и заведомо «чужое» значение, например элемент справочника.

Проверка ссылки через перечисление и общие модули БСП

В конфигурациях на базе Библиотеки стандартных подсистем есть готовые функции, которые не стоит дублировать собственным кодом. Например, ОбщегоНазначения.ЭтоСсылка(ТипЗначения) определяет, является ли тип ссылочным, а ОбщегоНазначения.ВидОбъектаПоСсылке(Ссылка) возвращает вид объекта строкой — «Документ», «Справочник» и т.д.

Если БСП в вашей конфигурации нет, тот же результат даёт сравнение через Метаданные.НайтиПоТипу(ТипЗнч(Значение)). Метод возвращает объект метаданных для переданного типа или Неопределено, если тип не прикладной. Дальше проверка сводится к тому же Метаданные.Документы.Содержит(...).

Отдельный частный случай — определить, что значение является именно ссылкой, а не объектом. Для этого сравнивают строковое имя типа или используют состав типов реквизита через метаданные. Простой практический критерий: у объекта доступно свойство ЭтоНовый() и табличные части «живые», у ссылки — только реквизиты, читаемые запросом к базе.

Сравнение способов проверки

ТипЗнч + Тип("ДокументСсылка.Имя")

Быстро и наглядно, но только для одного конкретного вида; ломается при переименовании документа.

Метаданные.Документы.Содержит(Значение.Метаданные())

Универсально для любых документов, работает и для ссылки, и для объекта; требует проверки на Неопределено.

Функции БСП (ОбщегоНазначения)

Готовое и протестированное решение, но доступно только в конфигурациях на базе БСП.

Особенности проверки на клиенте и в запросах

На тонком клиенте обращение к Метаданные недоступно — коллекция метаданных существует только на сервере. Если проверка нужна в клиентском коде, перенесите её в серверную функцию общего модуля с признаком «Сервер» и вызывайте оттуда, либо ограничьтесь сравнением ТипЗнч() с конкретным типом — оно работает и на клиенте.

В запросах проверка типа выполняется иначе — через оператор ССЫЛКА или функцию ТИПЗНАЧЕНИЯ():

ВЫБРАТЬ Товары.Ссылка

ИЗ Документ.РеализацияТоваровУслуг.Товары КАК Товары

ГДЕ Товары.Номенклатура ССЫЛКА Справочник.Номенклатура

Для реквизитов составного типа в запросе часто используют ВЫРАЗИТЬ(... КАК Документ.ИмяДокумента) — это одновременно и проверка, и приведение типа: несовпадающие значения превращаются в пустые ссылки указанного вида.

Типичные ошибки и проверка результата

Самая распространённая ошибка — сравнение ТипЗнч(Ссылка) с типом объекта или наоборот. Проверка молча возвращает Ложь, и логика алгоритма идёт по неверной ветке без каких-либо сообщений. Вторая частая проблема — попытка проверить тип через Строка(ТипЗнч(...)) и сравнение строк в разных локализациях: представления типов могут отличаться, поэтому сравнивайте сами типы, а не их текстовые представления.

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

Типичные ошибки
01
Сравнение ТипЗнч с типом объекта, когда в переменной ссылка — проверка всегда даёт Ложь.
02
Вызов Метаданные() у Неопределено или примитивного значения — ошибка выполнения в рабочей базе.
03
Сравнение строковых представлений типов — нестабильно при смене языка конфигурации.
04
Дублирование проверок вместо использования готовых функций БСП — лишний код и расхождение логики.
05
Проверка через Метаданные в клиентском коде — недоступность коллекции метаданных на тонком клиенте.
Итог

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

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

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

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

Сравните тип значения с типом вида «ДокументСсылка.ИмяДокумента» через ТипЗнч(). Для универсального варианта проверьте имя типа через метаданные и дополнительно убедитесь, что у значения отсутствуют признаки объекта — например, объект создаётся только через ПолучитьОбъект() или обработчики записи, поэтому по месту вызова обычно ясно, с чем вы работаете.

Можно ли проверить тип документа на тонком клиенте?

Да, но только сравнением ТипЗнч() с конкретным типом через функцию Тип(). Коллекция Метаданные на клиенте недоступна, поэтому универсальную проверку «это любой документ» выносите в серверную функцию общего модуля.

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

Используйте оператор ССЫЛКА в условии ГДЕ или функцию ТИПЗНАЧЕНИЯ() для сравнения с ТИП(Документ.ИмяДокумента). Для составных реквизитов удобен ВЫРАЗИТЬ(... КАК Документ.ИмяДокумента) — несовпадающие значения станут пустыми ссылками.

Что вернёт Метаданные.НайтиПоТипу для числа или строки?

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

Чем проверка через метаданные лучше сравнения строк?

Сравнение через Метаданные.Документы.Содержит() не зависит от языка конфигурации, не ломается при переименовании вида документа и работает одинаково для ссылки и объекта. Строковые сравнения хрупки по всем трём пунктам.

Как проверить, что документ не помечен на удаление и проведён?

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