При разработке отчетов на системе компоновки данных (СКД) в среде 1С:ERP Управление предприятием 2 программисты часто сталкиваются с ситуацией, когда данные в базе точно есть, запрос написан логично, но в результирующей таблице поле Контрагент остается пустым. Особенно часто это проявляется при попытке «дотянуться» до контрагента через документы расчетов или заказы. В этой статье мы подробно разберем, почему так происходит, и как правильно составить запрос, чтобы данные отображались корректно.
Рассмотрим типичную ситуацию. Нам необходимо построить отчет по движению безналичных денежных средств в разрезе заказов и контрагентов. Мы используем регистр накопления ДенежныеСредстваБезналичные. Типичный запрос, который на первый взгляд кажется верным, выглядит следующим образом:
ВЫБРАТЬ
ЕСТЬNULL(ДенежныеСредстваБезналичные.Заказ.Контрагент, ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)) КАК Контрагент,
ДенежныеСредстваБезналичные.Период КАК Период,
ДенежныеСредстваБезналичные.БанковскийСчет КАК БанковскийСчет,
ДенежныеСредстваБезналичные.Сумма КАК Сумма,
ДенежныеСредстваБезналичные.Заказ КАК Заказ
ИЗ
РегистрНакопления.ДенежныеСредстваБезналичные КАК ДенежныеСредстваБезналичные
ГДЕ
ДенежныеСредстваБезналичные.ХозяйственнаяОперация = &ХозяйственнаяОперация
Несмотря на использование ЕСТЬNULL и наличие данных в системе, в колонке «Контрагент» пользователь видит пустоту. Даже добавление левого соединения со справочником Контрагенты по прямой ссылке может не дать результата. Проанализируем причины этого поведения.
В архитектуре 1С:ERP многие реквизиты объектов жестко связаны с функциональными опциями. Одной из ключевых является опция «Независимо вести партнеров и контрагентов». Если в настройках системы эта опция выключена, 1С предполагает, что партнер и контрагент — это одна и та же сущность (связь один-к-одному).
Важный нюанс работы СКД: Система компоновки данных анализирует метаданные. Если функциональная опция, управляющая видимостью реквизита, выключена, СКД может автоматически подставлять NULL при обращении к этому полю через точку (разыменование), даже если физически в таблице базы данных значение заполнено. Это механизм платформы по обеспечению целостности настроек интерфейса и логики программы.
В регистре ДенежныеСредстваБезналичные измерение Заказ имеет составной тип данных. Оно может содержать ссылки на Заказ клиента, Заказ поставщику, Договор и другие документы. Когда мы пишем в запросе Заказ.Контрагент, система выполняет неявное левое соединение со всеми таблицами, входящими в этот составной тип.
Если хотя бы в одном из типов объектов, входящих в состав поля Заказ, отсутствует реквизит Контрагент, это может привести к некорректной работе оптимизатора запросов СКД. Кроме того, такое «разыменование» через точку является крайне непроизводительным для базы данных.
Проверенным способом обхода ограничений функциональных опций является явное левое соединение со справочником Контрагенты. При этом важно выбирать данные не из реквизита документа, а непосредственно из присоединенной таблицы справочника. Рассмотрим исправленный текст запроса:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ДенежныеСредстваБезналичные.Период КАК Период,
ДенежныеСредстваБезналичные.БанковскийСчет КАК БанковскийСчет,
ДенежныеСредстваБезналичные.Сумма КАК Сумма,
ДенежныеСредстваБезналичные.Заказ КАК Заказ,
Контрагенты.Ссылка КАК Контрагент
ИЗ
РегистрНакопления.ДенежныеСредстваБезналичные КАК ДенежныеСредстваБезналичные
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты
ПО ДенежныеСредстваБезналичные.Заказ.Контрагент = Контрагенты.Ссылка
ГДЕ
ДенежныеСредстваБезналичные.Период МЕЖДУ &НачалоПериода И &КонецПериода
И ДенежныеСредстваБезналичные.ХозяйственнаяОперация = &ХозяйственнаяОперация
Почему это работает? Обращаясь к таблице Справочник.Контрагенты напрямую, мы указываем СКД, что нам нужна ссылка из самого справочника. В этом случае механизм контроля функциональных опций на уровне «разыменования поля через заказ» не срабатывает, и данные выводятся в отчет.
Профессиональным подходом к разработке в ERP считается использование конструкции ВЫРАЗИТЬ. Это позволяет системе точно знать, к какой таблице обращаться, и повышает производительность. Если мы знаем, что нас интересуют, например, только заказы клиентов, запрос следует переписать так:
ВЫБРАТЬ
ВЫРАЗИТЬ(ДенежныеСредстваБезналичные.Заказ КАК Документ.ЗаказКлиента).Контрагент КАК Контрагент,
ДенежныеСредстваБезналичные.Сумма КАК Сумма
ИЗ
РегистрНакопления.ДенежныеСредстваБезналичные КАК ДенежныеСредстваБезналичные
Такой подход минимизирует количество неявных соединений и делает работу отчета более предсказуемой.
Проанализируем структуру данных ERP глубже. Регистр ДенежныеСредстваБезналичные предназначен для учета остатков денег на счетах, и Контрагент там не является первичной аналитикой (он «спрятан» внутри объекта расчетов).
Для получения связки Платеж — Заказ — Контрагент гораздо эффективнее использовать регистры взаиморасчетов:
РегистрНакопления.РасчетыСКлиентамиПоДокументамРегистрНакопления.РасчетыСПоставщикамиПоДокументамВ этих регистрах Контрагент является измерением. Если соединить данные о денежных средствах с данными из этих регистров по регистратору (документу оплаты), вы получите гарантированный доступ к контрагенту без каких-либо дополнительных ухищрений с разыменованием полей.
Разберем еще несколько моментов, которые могут влиять на результат:
РАЗРЕШЕННЫЕ в запросе заставляет систему проверять ограничения. Убедитесь, что у пользователей (и у администратора, если RLS настроен жестко) есть права не только на чтение документа заказа, но и на просмотр реквизита Контрагент внутри него.Заказ.Партнер. Если же нужна юридическая сущность — тогда используйте Контрагента через прямое соединение, как показано выше.Подводя итог, можно сказать: наиболее стабильным решением для вывода контрагента в отчетах по денежным средствам в 1С:ERP является явное левое соединение со справочником Контрагенты или обращение к регистрам расчетов, где эта аналитика вынесена в измерения. Это гарантирует обход ограничений функциональных опций и обеспечивает высокую скорость работы отчета.