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

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

Выбор действия по типу документа в 1С: методы, код и типичные ошибки

Как в 1С определить тип документа и выбрать нужную ветку обработки: ТипЗнч, Метаданные, ВидДокумента, условия в запросах и типичные ошибки разработчиков.

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

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

Все примеры применимы к управляемым формам и платформе 8.3, но большинство приёмов работает и в обычном приложении. Там, где поведение отличается, это отдельно отмечено.

Как определить тип документа через ТипЗнч и Тип

Самый прямой способ — получить тип значения функцией ТипЗнч() и сравнить его с конкретным типом через Тип(). Конструкция выглядит так:

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

// действия для реализации

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

// действия для поступления

КонецЕсли;

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

Поэтому переносимый код либо оборачивают в попытку, либо проверяют наличие метаданных заранее:

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

// безопасно использовать Тип("ДокументСсылка.РеализацияТоваровУслуг")

КонецЕсли;

Ветвление через Метаданные().Имя

Когда код должен работать в разных конфигурациях или тип документа заранее неизвестен, удобнее сравнивать не тип, а имя объекта метаданных:

ИмяДокумента = ДокументСсылка.Метаданные().Имя;

Если ИмяДокумента = "РеализацияТоваровУслуг" Тогда

// обработка

КонецЕсли;

Плюс подхода — код не падает, если документа нет: сравнение строк просто вернёт Ложь. Минус — сравнение строк медленнее сравнения типов и подвержено ошибкам из-за опечаток, которые синтаксическая проверка не поймает.

Метод Метаданные() доступен только на сервере. На тонком и веб-клиенте вызов Ссылка.Метаданные() недоступен, поэтому в клиентском коде определение типа делают через ТипЗнч() или выносят логику в серверную процедуру.

Когда строковое сравнение предпочтительнее

Строковое сравнение оправдано в универсальных обработках обмена, где список поддерживаемых документов хранится в настройках, и в коде расширений, где прямая ссылка на тип основной конфигурации может быть нежелательна. В типовом прикладном коде внутри одной конфигурации предпочтительнее сравнение типов — оно быстрее и проверяется компилятором.

Выбор по типу документа в запросах

В языке запросов ТипЗнч() недоступен, но есть собственные механизмы. Оператор ССЫЛКА проверяет принадлежность ссылки конкретной таблице:

ВЫБРАТ

Реестр.Документ КАК Документ

ИЗ

РегистрСведений.РеестрДокументов КАК Реестр

ГДЕ

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

Для выборки разных полей в зависимости от типа используют ВЫБОР КОГДА ... ТОГДА совместно с ССЫЛКА:

ВЫБОР

КОГДА Реестр.Документ ССЫЛКА Документ.РеализацияТоваровУслуг

ТОГДА "Продажа"

КОГДА Реестр.Документ ССЫЛКА Документ.ПоступлениеТоваровУслуг

ТОГДА "Закупка"

ИНАЧЕ "Прочее"

КОНЕЦ КАК ВидОперации

Чтобы обратиться к реквизиту, который есть только у конкретного вида документов, применяют оператор ВЫРАЗИТЬ:

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

Выбор действия в обработчиках событий и подписках

Типичный сценарий — подписка на событие ПриЗаписи для нескольких видов документов. Внутри обработчика источник приходит как ДокументОбъект, и ветвление строится по его типу:

Процедура ОбработкаЗаписиДокументаПриЗаписи(Источник, Отказ) Экспорт

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

ЗарегистрироватьОтгрузку(Источник.Ссылка);

ИначеЕсли ТипЗнч(Источник) = Тип("ДокументОбъект.ПоступлениеТоваровУслуг") Тогда

ОбновитьОстаткиЗаказа(Источник.Ссылка);

КонецЕсли;

КонецПроцедуры

Обратите внимание: в подписке источник — это объект, а не ссылка, поэтому сравнение идёт с ДокументОбъект.*. Это одна из самых частых ошибок: разработчик копирует проверку из кода, где был параметр-ссылка, и ветка никогда не срабатывает.

Если веток много, вместо длинной цепочки Если...ИначеЕсли удобнее соответствие, где ключ — имя документа, а значение — имя процедуры-обработчика. Такой код проще расширять и тестировать.

Порядок внедрения ветвления по типу
  1. 1
    Определите, что приходит на вход: ссылка или объект документа
  2. 2
    Выберите метод: ТипЗнч для фиксированной конфигурации, Метаданные().Имя — для переносимого кода, ССЫЛКА — для запросов
  3. 3
    Реализуйте ветки и добавьте ветку Иначе для неподдерживаемых типов
  4. 4
    Протестируйте каждый вид документа и случай с неподдерживаемым типом
  5. 5
    Проверьте работу на том клиенте, где будет выполняться код (тонкий, веб, сервер)

Ограничение типа в реквизитах и параметрах

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

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

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

ВызватьИсключение "Ожидался документ реализации";

КонецЕсли;

Такая явная проверка экономит часы отладки: вместо непонятной ошибки глубоко в логике вы получаете понятное сообщение в точке входа.

Сравнение способов определения типа

ТипЗнч + Тип

Быстро и проверяется компилятором; падает с ошибкой, если документа нет в конфигурации

Метаданные().Имя

Переносимо между конфигурациями; только сервер, медленнее, опечатки не ловятся

ССЫЛКА в запросе

Единственный способ внутри запроса; не применимо в коде вне запроса

Ограничение типа реквизита

Решает задачу без кода; требует изменения метаданных и не подходит для универсальных параметров

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

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

Вторая частая проблема — регистр имени при работе через Метаданные().Имя. Имя возвращается точно в том регистре, в котором задано в конфигураторе; сравнение с написанным иначе вариантом даст Ложь.

Типичные ошибки
01
Сравнение объекта с типом ДокументСсылка — ветка подписки на событие никогда не срабатывает
02
Использование Тип() с именем документа, которого нет в конфигурации, — ошибка выполнения вместо тихого пропуска ветки
03
Вызов Метаданные() на тонком клиенте — код недоступен, форма падает
04
Обращение к реквизиту составного поля в запросе без ВЫРАЗИТЬ — NULL или лишние соединения таблиц
05
Отсутствие ветки Иначе — неподдерживаемые документы молча проходят без обработки
Контрольные точки

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

Срабатывание ветки
Норма

При записи каждого вида документа выполняется его обработчик

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

Ветка молчит — проверьте, ссылка или объект сравнивается

Поведение на неподдерживаемом типе
Норма

Выполняется ветка Иначе с понятной реакцией

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

Код падает или ничего не происходит

Работа на тонком клиенте
Норма

Форма открывается и выполняет логику без ошибок

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

Ошибка вызова серверных методов — вынесите Метаданные() на сервер

Итог

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

Для выбора по типу документа используйте ТипЗнч с Тип в коде, ССЫЛКА и ВЫРАЗИТЬ в запросах, Метаданные().Имя — в переносимом коде. Всегда учитывайте различие ссылки и объекта и добавляйте ветку для неподдерживаемых типов.

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

Чем отличается ДокументСсылка от ДокументОбъект при проверке типа?

Это разные типы: ссылка — лёгкий идентификатор записи, объект — загруженные в память данные с возможностью изменения. ТипЗнч для них возвращает разные значения, поэтому проверка должна соответствовать тому, что реально приходит в параметр. При необходимости от объекта берите его Свойство Ссылка и сравнивайте уже её.

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

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

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

Да, на сервере доступна коллекция Метаданные.Документы: цикл по ней даёт объекты описания метаданных, у которых есть Имя и другие свойства. Так строят универсальные обработки, например список всех документов для выбора пользователем.

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

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

Почему в запросе поле составного типа возвращает NULL для реквизита?

Реквизит существует только в таблице конкретного документа. Для остальных видов документов в составном поле значение этого реквизита не определено, и запрос возвращает NULL. Используйте ВЫРАЗИТЬ с приведением к нужному типу и обрабатывайте NULL функцией ЕСТЬNULL.

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

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