Разработка и Конфигурация · 10 мин
Как в 1С проверить, что объект — это документ
Как в 1С определить, что объект является документом: ТипЗначения, Документы.ТипВсеСсылки, Метаданные.НайтиПоТипу. Примеры кода для ссылок и объектов.
При разработке обработок и процедур в 1С часто нужно определить, относится ли переданное значение к документам. Типичные сценарии — универсальная печатная форма, обработка ссылки произвольного типа, выгрузка данных или проверка перед записью. Платформа предлагает несколько способов такой проверки, и выбор зависит от того, что именно находится в переменной: ссылка, объект, тип или строка с именем вида.
Важно понимать разницу между ссылкой на документ (ДокументСсылка) и объектом документа (ДокументОбъект). Ссылка — это лёгкий идентификатор записи в базе, объект — полноценная структура данных в памяти с реквизитами, табличными частями и методами записи. Методы проверки для этих двух случаев немного отличаются, и путаница между ними — частая причина ошибок вида «Метод объекта не обнаружен».
Чем ссылка отличается от объекта документа
В 1С любой документ существует в двух ипостасях. ДокументСсылка.РеализацияТоваровУслуг — это указатель на запись в базе данных. Через ссылку доступны только ключевые поля (номер, дата, проведённость — через точку с обращением к базе), а для полноценной работы нужно вызвать метод ПолучитьОбъект(). ДокументОбъект.РеализацияТоваровУслуг — это данные, загруженные в память: реквизиты, табличные части, движения.
Это различие влияет на проверку типа. Функция ТипЗнч() для ссылки вернёт тип вида «ДокументСсылка.РеализацияТоваровУслуг», а для объекта — «ДокументОбъект.РеализацияТоваровУслуг». Если код ожидает ссылку, а получил объект (или наоборот), простые сравнения типов дадут ложный результат. Поэтому первый шаг — понять, с чем работает ваша процедура.
Проверка ссылки через Документы.ТипВсеСсылки()
Самый надёжный способ определить, что ссылка принадлежит документу любого вида, — использовать коллекцию типов всех документов конфигурации. Метод Документы.ТипВсеСсылки() возвращает описание типов, включающее ссылки всех видов документов, а метод СодержитТип() проверяет вхождение конкретного типа.
Функция ЭтоДокумент(Значение) Экспорт
Если Значение = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Возврат Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение));
КонецФункцииТакой подход работает для любой конфигурации без перечисления видов документов вручную. Если в конфигурацию добавят новый вид документа, функция продолжит работать корректно. Аналогичные коллекции существуют и для других объектов: Справочники.ТипВсеСсылки(), ПланыСчетов.ТипВсеСсылки(), БизнесПроцессы.ТипВсеСсылки() — по тому же принципу можно проверять принадлежность к любому семейству объектов.
Если нужно проверить не «документ вообще», а конкретный вид, используйте прямое сравнение типа: ТипЗнч(Ссылка) = Тип("ДокументСсылка.ПоступлениеТоваровУслуг"). Это быстрее и читабельнее, когда вид документа известен заранее.
Проверка через метаданные: НайтиПоТипу и НайтиПоПолномуИмени
Второй подход — обратиться к метаданным. Метод Метаданные.НайтиПоТипу(ТипЗнч(Значение)) возвращает объект описания метаданного, которому соответствует значение. Дальше достаточно проверить, входит ли этот объект в коллекцию Метаданные.Документы.
Функция ЭтоДокументПоМетаданным(Значение) Экспорт
Мета = Метаданные.НайтиПоТипу(ТипЗнч(Значение));
Если Мета = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Возврат Метаданные.Документы.Содержит(Мета);
КонецФункцииЭтот способ универсален: он одинаково работает и для ссылок, и для объектов, потому что метаданные у них общие. Дополнительный бонус — через Мета.Имя и Мета.ПолноеИмя() вы сразу получаете вид документа, что полезно для ветвления логики или формирования сообщений пользователю.
Обратная задача — определить тип по строковому имени — решается через Метаданные.НайтиПоПолномуИмени("Документ.РеализацияТоваровУслуг"). Если по имени найден объект метаданных и его родитель — «Документ», значит, имя описывает документ. Это пригождается при разборе настроек, где вид объекта хранится строкой.
Проверка объекта документа в памяти
Когда в переменной находится ДокументОбъект (например, внутри обработки проведения, перед записью или после ПолучитьОбъект()), коллекция Документы.ТипВсеСсылки() не подойдёт напрямую — она содержит типы ссылок, а не объектов. Здесь есть два рабочих варианта.
Первый — проверка через метаданные, описанная выше: Метаданные.НайтиПоТипу() корректно разрешает и типы объектов. Второй — взять ссылку объекта и проверить её: у любого объекта документа есть свойство Ссылка, даже если документ ещё не записан (у нового объекта ссылка может быть пустой, но тип у неё всё равно документный).
// Проверка объекта документа через его ссылку
Функция ЭтоОбъектДокумента(Объект) Экспорт
Попытка
Возврат Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Объект.Ссылка));
Исключение
Возврат Ложь;
КонецПопытки;
КонецФункцииОбращение к свойству Ссылка через попытку защищает от значений, у которых этого свойства нет — примитивных типов, структур, строк. Однако злоупотреблять конструкцией «Попытка–Исключение» не стоит: она маскирует ошибки. Лучше сначала отсеять явно неподходящие значения проверкой на Неопределено и простые типы.
Проверка в запросе и на форме
Определение вида документа в запросе
В языке запросов проверка типа выполняется оператором ССЫЛКА или функцией ТИПЗНАЧЕНИЯ(). Например, условие ГДЕ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг отбирает записи только по нужному виду. Для проверки «любой документ» перечислять все виды не требуется — обычно в запросах важен конкретный вид или сравнение ТИПЗНАЧЕНИЯ(Поле) = ТИП(Документ.ПриходныйКассовыйОрдер).
Проверка параметра на управляемой форме
В обработчиках формы (например, при расширении формы списка или подборе) значение часто приходит как Произвольный или ПолеФормы. Прежде чем обращаться к реквизитам документа, проверьте тип через ТипЗнч() и коллекцию Документы.ТипВсеСсылки(). Это защитит от падения обработчика, когда пользователь выберет элемент справочника вместо документа.
- 1Определите, что в переменной: ссылка, объект или строка с именем вида
- 2Для ссылки примените Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение))
- 3Для объекта используйте Метаданные.НайтиПоТипу() или проверку типа его свойства Ссылка
- 4Для строки найдите метаданные через Метаданные.НайтиПоПолномуИмени() и проверьте родителя
- 5Проверьте результат на тестовых значениях: документе, справочнике, Неопределено
Типичные ошибки и как их избежать
Самая распространённая ошибка — сравнение типа со строкой: ТипЗнч(Ссылка) = "ДокументСсылка.РеализацияТоваровУслуг". Такое сравнение всегда ложно, потому что слева объект типа «Тип», а справа строка. Правильно — Тип("ДокументСсылка.РеализацияТоваровУслуг") с обеих сторон как типы.
Вторая ошибка — использование функции ЭтоДокумент(), написанной для ссылок, к объектам документов и наоборот. Третья — проверка через НайтиПодстроку(Строка(ТипЗнч(Значение)), "Документ"): строковое представление типа зависит от локализации и не предназначено для логики. Также не забывайте про значение Неопределено — вызов ТипЗнч(Неопределено) вернёт тип «Неопределено», который корректно не пройдёт проверки, но обращение к свойствам такого значения вызовет исключение.
Какой способ выбрать в вашей ситуации
Для большинства задач достаточно проверки через Документы.ТипВсеСсылки() — она короткая, быстрая и не требует обращения к базе. Проверку через метаданные выбирайте, когда нужна универсальность (ссылки и объекты в одной функции) или когда помимо факта «это документ» требуется имя вида. Прямое сравнение типов уместно, когда вид документа фиксирован и важна максимальная читаемость кода.
Сравнение способов проверки
Быстро и кратко, но работает только со ссылками; для объектов нужна обёртка через свойство Ссылка
Универсально для ссылок и объектов, сразу даёт имя вида; чуть многословнее и требует проверки на Неопределено
Идеально для фиксированного вида документа; не подходит, когда видов много или они неизвестны заранее
Что важно запомнить
Разделяйте ссылку и объект документа — для них применяются разные приёмы проверки. Для ссылок используйте Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)), для универсальной проверки — Метаданные.НайтиПоТипу(). Не вызывайте ПолучитьОбъект() ради определения типа и всегда отсекайте Неопределено.
Частые вопросы
Как проверить, что значение — документ конкретного вида?
Сравните тип напрямую: ТипЗнч(Ссылка) = Тип("ДокументСсылка.РеализацияТоваровУслуг"). Имя вида указывается так, как оно задано в конфигураторе. Для объекта документа используйте Тип("ДокументОбъект.РеализацияТоваровУслуг") или проверяйте тип его свойства Ссылка.
Работает ли ТипВсеСсылки() на сервере и на клиенте?
Да, менеджер Документы и его метод ТипВсеСсылки() доступны и на сервере, и на толстом, и на тонком клиенте. Метаданные.НайтиПоТипу() на тонком клиенте недоступен — универсальные функции с метаданными размещайте в серверных общих модулях.
Как отличить документ от справочника в одной функции?
Определите метаданные значения через Метаданные.НайтиПоТипу(), затем проверьте вхождение: Метаданные.Документы.Содержит(Мета) — документ, Метаданные.Справочники.Содержит(Мета) — справочник. Функция может возвращать строку с видом объекта для дальнейшего ветвления.
Почему проверка через Строка(ТипЗнч()) считается плохой практикой?
Строковое представление типа предназначено для отображения пользователю и может меняться в зависимости от языка интерфейса и версии платформы. Логика, построенная на поиске подстроки «Документ» в таком представлении, ненадёжна и трудно отлаживается. Используйте сравнение типов и коллекции метаданных.
Как проверить тип в запросе, если регистратор составного типа?
Используйте оператор ССЫЛКА: ГДЕ Движения.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг. Для сравнения с параметром применяйте ТИПЗНАЧЕНИЯ(Регистратор) = ТИПЗНАЧЕНИЯ(&Ссылка). Перечислять все виды документов для условия «любой документ» в запросе обычно не требуется — отбор идёт по конкретным видам.
Что вернёт проверка для пустой ссылки документа?
Пустая ссылка документа сохраняет свой тип: Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(ПустаяСсылка)) вернёт Истина. Если нужно дополнительно убедиться, что ссылка не пустая, добавьте проверку ЗначениеЗаполнено(Ссылка) или сравнение с Документы.ВидДокумента.ПустаяСсылка().