Что за документ лежит в переменной: определяем вид ссылки в 1С 8.3
Содержание
Проверить, что за документ в 1С, проще всего сравнением типов: ТипЗнч(Значение) = Тип("ДокументСсылка.РеализацияТоваровУслуг"). Если вид заранее неизвестен, сначала убедитесь, что это вообще документ — Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)), — а затем узнайте его реальное имя через Значение.Метаданные().Имя. В запросе то же делают оператор ССЫЛКА и функция ТИПЗНАЧЕНИЯ().
Частая ошибка — сравнивать строки: Строка(Значение) или Строка(ТипЗнч(Значение)). Так вы получите представление для пользователя — номер, дату или синоним, — которое меняется при переименовании и смене языка. Тип надо сравнивать с типом, а имя брать из метаданных. Всё ниже относится к платформе 8.3 целиком и не зависит от конфигурации: БП, ЗУП и УТ работают одинаково, отличаются только имена документов.
Ссылка, объект и тип: из чего состоит документ в платформе
У каждого документа в конфигурации платформа создаёт несколько типов. Путаница между ними — главный источник ошибок при проверке.
| Тип | Пример | Что это | Где встречается |
|---|---|---|---|
ДокументСсылка.<Имя> | ДокументСсылка.ПоступлениеТоваровУслуг | Указатель на запись в базе | Реквизиты, регистраторы, параметры процедур |
ДокументОбъект.<Имя> | ДокументОбъект.ПоступлениеТоваровУслуг | Сам документ с данными, который можно изменить и записать | Модуль объекта, обработчики ПередЗаписью |
ДокументМенеджер.<Имя> | Документы.ПоступлениеТоваровУслуг | Менеджер: создание, поиск, печать | Код вида Документы.Имя.СоздатьДокумент() |
| Объект метаданных | Метаданные.Документы.ПоступлениеТоваровУслуг | Описание документа в конфигурации: имя, синоним, реквизиты | Анализ структуры, универсальный код |
Что из этого следует на практике:
- 🔹 В реквизите составного типа, в поле
Регистраторили в параметре процедуры почти всегда лежит ссылка, а не объект. - 🔹
Тип("ДокументСсылка.Имя")иТип("ДокументОбъект.Имя")— разные типы. Ссылку с типом объекта сравнение не пройдёт. - 🔹 Имя (
РеализацияТоваровУслуг) — техническое, по нему пишут код. Синоним — то, что видит пользователь в заголовке формы. Синоним можно поменять в конфигураторе, имя в коде так просто не меняют.
Если в коде у вас объект, а нужна ссылка, берите Объект.Ссылка. Для нового, ещё не записанного документа ссылка пустая — об этом ниже.
Проверка типа документа в коде: пять рабочих способов
1. Конкретный вид документа
Самый частый случай: нужно понять, реализация это или нет.
Если ТипЗнч(Значение) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
// обрабатываем реализацию
КонецЕсли;
Работает на клиенте и на сервере, обращения к базе нет. Строку внутри Тип() пишите точно как имя в конфигураторе. Опечатка даст ошибку времени выполнения Тип не определен.
2. Один из нескольких видов
Когда подходит любой из списка, удобнее ОписаниеТипов, чем цепочка ИЛИ:
ДокументыДвижения = Новый ОписаниеТипов(
"ДокументСсылка.ПоступлениеТоваровУслуг, ДокументСсылка.РеализацияТоваровУслуг, ДокументСсылка.ПеремещениеТоваров");
Если ДокументыДвижения.СодержитТип(ТипЗнч(Значение)) Тогда
// это один из трёх документов
КонецЕсли;
Описание типов можно создать один раз в начале процедуры и проверять им строки таблицы в цикле.
3. Любой документ, вид неважен
Если Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
// в переменной ссылка на какой-то документ
КонецЕсли;
ТипВсеСсылки() есть и у других менеджеров: Справочники.ТипВсеСсылки(), ПланыВидовХарактеристик.ТипВсеСсылки(). Так отличают документ от справочника в поле составного типа.
4. Реальное имя и синоним из метаданных
Когда вид заранее неизвестен и его надо узнать, спросите метаданные:
МД = Значение.Метаданные();
ИмяДокумента = МД.Имя; // например, "РеализацияТоваровУслуг"
ПолноеИмя = МД.ПолноеИмя(); // "Документ.РеализацияТоваровУслуг"
ДляПользователя = МД.Синоним; // название, которое видно в программе
ЭтоДокумент = Метаданные.Документы.Содержит(МД);
Есть и вариант без вызова метода у ссылки — Метаданные.НайтиПоТипу(ТипЗнч(Значение)). Для примитивных типов (строка, число, Неопределено) он вернёт Неопределено, и это тоже удобно как проверка.
Вызывать .Метаданные() у значения Неопределено нельзя: получите Метод объекта не обнаружен (Метаданные). Сначала проверка типа, потом обращение к метаданным.
5. Функции БСП в типовых конфигурациях
В БП 3.0, ЗУП 3.1, УТ 11 и других конфигурациях на Библиотеке стандартных подсистем есть готовые функции общего модуля ОбщегоНазначения:
- ✅
ОбщегоНазначения.ЭтоДокумент(ОбъектМетаданных)— принимает объект метаданных, а не ссылку:ОбщегоНазначения.ЭтоДокумент(Значение.Метаданные()). - ✅
ОбщегоНазначения.ЭтоСсылка(Тип)— проверяет, что тип вообще ссылочный.
В собственной обработке или в конфигурации без БСП их нет — пользуйтесь способами 1–4.
Какой способ выбрать
| Задача | Способ | Обращение к базе | Где работает |
|---|---|---|---|
| Это реализация? | ТипЗнч = Тип(...) | Нет | Клиент и сервер |
| Один из списка | ОписаниеТипов.СодержитТип | Нет | Клиент и сервер |
| Это вообще документ? | Документы.ТипВсеСсылки() | Нет | Сервер |
| Как он называется | .Метаданные().Имя, Синоним | Нет | Сервер |
| Он реально есть в базе? | Запрос по ссылке | Да | Сервер |
Метаданные и менеджеры документов надёжнее трогать в серверной процедуре. На клиенте ограничьтесь сравнением через Тип(), остальное выносите в &НаСервереБезКонтекста.
Как узнать, что это за документ, в интерфейсе пользователя
Программировать не обязательно. Пользователю и консультанту хватает нескольких приёмов.
Заголовок формы
Откройте документ двойным щелчком. В заголовке окна стоит его представление: синоним вида, номер и дата. Это ответ «для людей», но не техническое имя.
Навигационная ссылка
В заголовке открытой формы есть значок ссылки — команда получения навигационной ссылки. Скопируйте ссылку, и вы увидите строку вида:
e1cib/data/Документ.РеализацияТоваровУслуг?ref=8f3e00155d0a1b2c11ee5d3a9b7c4e10
После Документ. идёт реальное имя вида документа из конфигурации, после ref= — уникальный идентификатор записи. Тот же вид программно вернёт функция ПолучитьНавигационнуюСсылку(Значение). Ссылку можно отправить коллеге: она откроет тот же документ через главное меню, команду перехода по ссылке.
Все функции
Если документ нужно найти по виду, включите полный список объектов: Главное меню (☰) → Сервис → Параметры, флажок «Отображать команду «Все функции»». Затем Главное меню → Все функции → Документы — там все виды документов конфигурации под их синонимами.
Отчёты и журналы
В оборотно-сальдовой ведомости, карточке счёта и отчётах по регистрам документ-основание движения показан в колонке «Регистратор» или «Документ». Двойной щелчок по нему открывает форму — дальше смотрите заголовок или навигационную ссылку. В журналах документов в одном списке лежат разные виды, и колонка с видом документа подсказывает, что перед вами.
Если нужно понять, откуда документ взялся, в форме документа через меню Ещё откройте структуру подчинённости: там видны основание и введённые на его основании документы.
Разбираем структуру документа в Конфигураторе
Когда имя известно, а нужно понять, что внутри, идите в Конфигуратор.
- Запустите базу в режиме «Конфигуратор» и откройте дерево:
Конфигурация → Открыть конфигурацию. - Разверните ветку «Документы». Начните печатать имя прямо в дереве — курсор перейдёт к совпадению. Имя берите из навигационной ссылки.
- Откройте окно редактирования документа. На закладках видно:
- 📌 Основные — имя, синоним, комментарий;
- 📌 Данные — реквизиты шапки и табличные части с типами;
- 📌 Нумерация — длина и тип номера, периодичность;
- 📌 Движения — проводится ли документ и в какие регистры пишет.
- Чтобы найти, где этот вид используется в других объектах, вызовите в контекстном меню документа команду «Поиск ссылок на объект». Список покажет реквизиты составного типа, журналы, регистры с ним в регистраторах.
Тип значения в отладчике
Если непонятно, что лежит в переменной во время выполнения, поставьте точку останова и откройте «Вычислить выражение» (Shift+F9). Введите ТипЗнч(Значение) или Значение.Метаданные().ПолноеИмя(). В табло и окне вычисления у значения есть колонка «Тип» — там сразу видно ДокументСсылка.<Имя>.
Отладку в рабочей базе включайте только с согласия администратора: пока выполнение стоит на точке останова, сеанс пользователя висит. Ничего не меняйте в конфигурации рабочей базы без резервной копии.
Неопределено, пустая ссылка и битая ссылка: в чём разница
Реквизит составного типа может хранить три «ненастоящих» значения. Их нужно различать до любых проверок вида.
| Состояние | Как выглядит | Проверка | ЗначениеЗаполнено() |
|---|---|---|---|
Неопределено | Поле пустое, тип не выбран | Значение = Неопределено | Ложь |
| Пустая ссылка | Тип выбран, документ — нет | Значение.Пустая() | Ложь |
| Битая ссылка | <Объект не найден> (…) | Запрос к таблице документа | Истина |
| Нормальная ссылка | Номер и дата | Тип совпадает, запись найдена | Истина |
Ключевые моменты:
- 🔸 У пустой ссылки тип уже есть.
ТипЗнч(Документы.РеализацияТоваровУслуг.ПустаяСсылка())вернёт тип реализации, хотя документа нет. - 🔸
ЗначениеЗаполнено()не ловит битую ссылку: идентификатор в ней есть, а записи в базе уже нет. Такое бывает после удаления помеченных объектов при оставшихся ссылках или после неудачного обмена. - 🔸 Новый, ещё не записанный документ имеет пустую
Ссылка. В обработчикеПередЗаписьюпроверяйтеЭтоНовый(), а не заполненность ссылки.
Универсальная функция «что это за документ»
Функция собирает все проверки вместе и возвращает понятную структуру:
&НаСервереБезКонтекста
Функция ОписаниеДокумента(Значение)
Результат = Новый Структура("ЭтоДокумент, Имя, Синоним, Существует", Ложь, "", "", Ложь);
Если Значение = Неопределено Тогда
Возврат Результат;
КонецЕсли;
Если Не Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
Возврат Результат;
КонецЕсли;
МД = Значение.Метаданные();
Результат.ЭтоДокумент = Истина;
Результат.Имя = МД.Имя;
Результат.Синоним = МД.Синоним;
Если Не Значение.Пустая() Тогда
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 ИСТИНА КАК Есть ИЗ " + МД.ПолноеИмя() + " ГДЕ Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Значение);
Результат.Существует = Не Запрос.Выполнить().Пустой();
КонецЕсли;
Возврат Результат;
КонецФункции
Для битой ссылки функция вернёт ЭтоДокумент = Истина и Существует = Ложь. Запрос лёгкий: читается одна запись по индексу, объект целиком в память не грузится — в отличие от Значение.ПолучитьОбъект().
Определение вида документа в запросе
В запросах тип проверяют на стороне СУБД — это быстрее, чем выбирать всё и фильтровать в цикле.
Отбор по виду: ССЫЛКА и ТИПЗНАЧЕНИЯ
Два равнозначных условия. Пример по регистру бухгалтерии в БП 3.0 — отобрать движения только от реализаций:
ВЫБРАТЬ
Хозрасчетный.Регистратор КАК Регистратор,
ВЫРАЗИТЬ(Хозрасчетный.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент КАК Контрагент
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
Хозрасчетный.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
И Хозрасчетный.Период МЕЖДУ &НачалоПериода И &КонецПериода
Вместо ССЫЛКА можно написать ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор) = ТИП(Документ.РеализацияТоваровУслуг). Результат тот же; ССЫЛКА короче и читается проще.
ВЫРАЗИТЬ нужен, чтобы получить реквизит конкретного вида из поля составного типа. Без него платформа соединяет таблицы всех возможных регистраторов, и запрос тяжелеет.
Какие виды документов есть в выборке
Если надо узнать, какие документы вообще двигали регистр за период, сгруппируйте по типу:
ВЫБРАТЬ
ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор) КАК ТипДокумента,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Хозрасчетный.Регистратор) КАК Документов
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
Хозрасчетный.Период МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор)
В результате поле ТипДокумента — значение типа Тип. Человеческое название получите в коде: Метаданные.НайтиПоТипу(Выборка.ТипДокумента).Синоним.
Поиск битых ссылок запросом
Битая ссылка в запросе видна так: поле заполнено, а соединение с таблицей документа не нашло записи.
ВЫБРАТЬ
Т.Ссылка КАК Документ,
Т.ДокументОснование КАК Основание
ИЗ
Документ.СчетФактураВыданный КАК Т
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Р
ПО Т.ДокументОснование = Р.Ссылка
ГДЕ
Т.ДокументОснование ССЫЛКА Документ.РеализацияТоваровУслуг
И Р.Ссылка ЕСТЬ NULL
И НЕ Т.ДокументОснование = ЗНАЧЕНИЕ(Документ.РеализацияТоваровУслуг.ПустаяСсылка)
Имена документа и реквизита замените на свои — проверьте их в Конфигураторе. Схема запроса от этого не меняется.
Где ошибаются при проверке типа и как этого избежать
Ещё три привычки, которые экономят время на отладке:
- 🛠 Не открывайте объект ради проверки.
ПолучитьОбъект()читает документ со всеми табличными частями. Чтобы узнать вид, объект не нужен, а для проверки существования хватает запроса. - 🛠 Не определяйте вид по номеру. Префиксы номеров задаются настройками организации и узла обмена, у разных видов они могут совпадать.
- 🛠 Держите проверку типа в одном месте. Если тот же список видов нужен в нескольких модулях, вынесите
ОписаниеТиповв функцию общего модуля, а не копируйте строку с именами.