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