При работе в классических конфигурациях на платформе 1С:Предприятие 8, таких как «Управление торговлей 10.3» или «Управление торговлей 2.1», пользователи и разработчики часто сталкиваются со специфической ошибкой при попытке получить детальные данные из отчета (выполнить расшифровку). Ошибка выглядит следующим образом: {Отчет.ПродажиСОстатками.МодульОбъекта(4058)}: Поле объекта не обнаружено (УниверсальныйОтчет). В этой статье мы подробно разберем, почему возникает эта коллизия и как правильно настроить объекты конфигурации, чтобы расшифровка работала корректно.
Для начала проанализируем ситуацию с точки зрения архитектуры системы. В старых редакциях УТ и УПП большинство отчетов не являются самостоятельными единицами в плане логики компоновки данных. Они построены по принципу «обертки» вокруг одного базового объекта — Универсального отчета.
Когда вы открываете отчет, например, «Продажи», система на самом деле создает экземпляр этого отчета, внутри которого есть реквизит УниверсальныйОтчет с типом ОтчетОбъект.УниверсальныйОтчет. Именно в этом внутреннем объекте хранятся все настройки: группировки, отборы, выбранные поля и оформление. Проблема возникает в момент «прыжка» из одного отчета в другой (расшифровка). Если целевой отчет, в который мы пытаемся провалиться, не имеет нужной структуры метаданных, программный код модуля расшифровки «спотыкается» об отсутствие поля УниверсальныйОтчет.
Рассмотрим подробнее сценарий возникновения ошибки. Проанализируем типовой код, на котором происходит сбой:
УниверсальныйОтчетРасшифровка = ?(ОтчетРасшифровкаУниверсальный, ОтчетРасшифровка, ОтчетРасшифровка.УниверсальныйОтчет);
В этой строке переменная ОтчетРасшифровка содержит объект отчета, который должен открыться для детализации. Если этот объект не является «универсальным» по своей сути или в его метаданных забыли добавить соответствующий реквизит, попытка обращения к ОтчетРасшифровка.УниверсальныйОтчет вызывает исключение, так как система не видит такого поля в структуре объекта.
Как правило, это случается в двух случаях:
Это самый надежный способ, который позволяет отчету полноценно участвовать в механизме типовых расшифровок. Разберем по шагам, что необходимо сделать в конфигураторе:
УниверсальныйОтчетОтчетОбъект.УниверсальныйОтчетПосле добавления реквизита в метаданные, ошибка «Поле объекта не обнаружено» исчезнет, так как обращение ОтчетРасшифровка.УниверсальныйОтчет станет легитимным.
Просто добавить реквизит в метаданные часто бывает недостаточно. Нужно, чтобы этот объект был создан в памяти в момент инициализации отчета. В противном случае мы получим ошибку «Значение не является значением объектного типа», так как реквизит будет равен Неопределено.
Посмотрим на пример кода, который должен присутствовать в модуле объекта или в процедуре ПередОткрытием формы отчета:
// В модуле объекта или при создании
УниверсальныйОтчет = Отчеты.УниверсальныйОтчет.Создать();
Это гарантирует, что когда основной отчет (например, «Продажи») попытается передать свои настройки интервалов или оформления в отчет расшифровки, ему будет куда их записывать.
Если по каким-то причинам вы не можете менять метаданные целевого отчета (например, это сложный внешний отчет), мы можем модифицировать сам алгоритм вызова расшифровки. Проанализируем ситуацию: нам нужно проверить наличие реквизита перед тем, как к нему обращаться.
Используем безопасный метод обращения через попытку или проверку метаданных:
// Вариант с использованием Попытка...Исключение
Попытка
УниверсальныйОтчетРасшифровка = ОтчетРасшифровка.УниверсальныйОтчет;
Исключение
// Если реквизита нет, считаем, что сам объект ОтчетРасшифровка и есть целевой объект
УниверсальныйОтчетРасшифровка = ОтчетРасшифровка;
КонецПопытки;
Также можно применить проверку через функцию ОбщегоНазначения, если она есть в вашей конфигурации:
Если ОбщегоНазначения.ЕстьРеквизитОбъекта("УниверсальныйОтчет", ОтчетРасшифровка) Тогда
УниверсальныйОтчетРасшифровка = ОтчетРасшифровка.УниверсальныйОтчет;
Иначе
УниверсальныйОтчетРасшифровка = ОтчетРасшифровка;
КонецЕсли;
Рассмотрим подробнее нюанс, упомянутый в обсуждении: внешние отчеты подключаются иначе. Если ваш отчет не встроен в конфигурацию, а запускается как внешний файл, стандартная проверка Метаданные.НайтиПоТипу может вернуть некорректный результат.
В этом случае при передаче параметров расшифровки УниверсальныйОтчетТекущий (исходный отчет) пытается скопировать свои свойства в УниверсальныйОтчетРасшифровка. Если вы работаете с внешним отчетом, убедитесь, что код копирования настроек не выполняется для объектов, которые не поддерживают интерфейс УниверсальныйОтчет.
Пример «ломающегося» кода из практики:
УниверсальныйОтчетРасшифровка.Интервалы = УниверсальныйОтчетТекущий.Интервалы.Скопировать;
УниверсальныйОтчетРасшифровка.ВариантОформления = УниверсальныйОтчетТекущий.ВариантОформления;
// ... и так далее
Важный совет: Если вы столкнулись с тем, что после прохода цикла по созданию отчета реквизит «пропадает» (как в сообщении №8), проверьте, не происходит ли переинициализация переменной ОтчетРасшифровка внутри условий Если...ИначеЕсли. Часто разработчики создают новый объект, забывая пробросить в него ссылку на созданный внутренний УниверсальныйОтчет.
Чтобы окончательно решить проблему «Поле объекта не обнаружено (УниверсальныйОтчет)», мы рекомендуем следующий алгоритм действий:
УниверсальныйОтчет с правильным типом.Создать() для этого реквизита.ОтчетРасшифровка в момент возникновения ошибки.Соблюдение этих правил позволит вам избежать конфликтов в механизме детализации данных и обеспечит стабильную работу аналитических инструментов в 1С.