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

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

При доработке типовых универсальных отчетов, построенных на базе объекта ПостроительОтчета (часто встречающихся в конфигурациях «Управление торговлей 10.3», «Управление производственным предприятием 1.3» и «Комплексная автоматизация 1.1»), разработчики сталкиваются с задачей добавления измерений строк. Если стандартный реквизит объекта добавляется тривиально — например, через обращение Контрагент.Наименование, — то группировка по дополнительному свойству (значению из плана видов характеристик СвойстваОбъектов) требует понимания внутреннего механизма формирования псевдонимов полей.

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

Внутреннее устройство механизма свойств и категорий

В типовом универсальном отчете за подключение дополнительных реквизитов отвечает процедура ДобавитьВТекстЗапросаСвойстваИКатегории. Механизм динамически модифицирует исходный текст запроса: к таблицам объектов добавляются левые соединения с регистром сведений ЗначенияСвойствОбъектов.

Проанализируем фрагмент запроса, который формируется системой автоматически при включенном режиме свойств:


{ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК КонтрагентСвойство392584bb9ca211e49e1b0015172a9709
    ПО КонтрагентСвойство392584bb9ca211e49e1b0015172a9709.Объект = Взаиморасчеты.Контрагент
    И КонтрагентСвойство392584bb9ca211e49e1b0015172a9709.Свойство = &ПараметрКонтрагентСвойство392584bb9ca211e49e1b0015172a9709}

В секцию полей выборки при этом добавляются следующие конструкции:


КонтрагентСвойство392584bb9ca211e49e1b0015172a9709.Значение КАК КонтрагентСвойство392584bb9ca211e49e1b0015172a9709Значение,
ПРЕДСТАВЛЕНИЕ(КонтрагентСвойство392584bb9ca211e49e1b0015172a9709.Значение) КАК КонтрагентСвойство392584bb9ca211e49e1b0015172a9709ЗначениеПредставление

Обратим внимание на имя поля: оно формируется путем слияния имени исходного измерения, префикса Свойство, шестнадцатеричного строкового представления УникальныйИдентификатор() без дефисов и постфикса Значение.

Способ 1. Динамическое определение имени поля свойства (Рекомендуемый)

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

Разберем реализацию по шагам:

  1. Находим нужное свойство в справочнике или плане видов характеристик (например, по наименованию или коду).
  2. Получаем строковый GUID свойства и удаляем из него дефисы.
  3. Формируем результирующее имя измерения.
  4. Добавляем сформированное измерение в построитель отчета.

// 1. Поиск нужного свойства
СвойствоСсылка = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("ОтветственныйЗаПлатежи");

Если ЗначениеЗаполнено(СвойствоСсылка) Тогда
    // 2. Очистка GUID от символов дефиса
    СтрГуид = СтрЗаменить(Строка(СвойствоСсылка.УникальныйИдентификатор()), "-", "");
    
    // 3. Формирование системного имени поля
    ИмяПоляСвойства = "КонтрагентСвойство" + СтрГуид + "Значение";
    
    // 4. Добавление группировки в универсальный отчет
    ОтчетОстатки.УниверсальныйОтчет.ДобавитьИзмерениеСтроки(ИмяПоляСвойства, ТипИзмеренияПостроителяОтчета.Элементы);
КонецЕсли;

Обязательный порядок инициализации отчета

Частая ошибка, с которой сталкиваются разработчики — исключение при вызове метода ДобавитьИзмерениеСтроки или отсутствие группировки в итоговом результате. Выясним причину этой проблемы: она заключается в нарушении последовательности этапов подготовки отчета.

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

  1. Регистрация связи поля со свойствами: вызывается метод связывания поля запроса с назначением свойств, например УниверсальныйОтчет.ДобавитьСвойстваИКатегорииДляПоля(...) с указанием значения ПланыВидовХарактеристик.НазначенияСвойствКатегорийОбъектов.Справочник_Контрагенты.
  2. Включение признака использования: установка флага использования свойств и категорий должна происходить до генерации окончательного текста запроса.
  3. Формирование текста запроса: вызывается процедура добавления левых соединений (ДобавитьВТекстЗапросаСвойстваИКатегории), после чего результирующий текст помещается в свойство ПостроительОтчета.Текст.
  4. Обновление доступных полей: вызывается переинициализация структуры или метод ПостроительОтчета.ЗаполнитьНастройки(), чтобы построитель перечитал поля выборки.
  5. Установка измерений: только после выполнения предыдущих шагов можно вызывать ДобавитьИзмерениеСтроки(...).

Способ 2. Явное соединение в исходном тексте запроса

Если в отчете требуется группировка исключительно по одному конкретному свойству и динамический выбор остальных реквизитов не нужен, типовой механизм с генерацией GUID можно обойти. Это позволяет существенно упростить код и повысить производительность запроса.

Рассмотрим, как связать данные напрямую в запросе построителя:


ТекстЗапроса = 
"ВЫБРАТЬ
|   Взаиморасчеты.Контрагент КАК Контрагент,
|   ЕСТЬNULL(СвойстваКонтрагентов.Значение, НЕОПРЕДЕЛЕНО) КАК ОтветственныйЗаПлатежи,
|   Взаиморасчеты.СуммаОстаток КАК СуммаОстаток
|{ВЫБРАТЬ
|   Контрагент.*,
|   ОтветственныйЗаПлатежи.*,
|   СуммаОстаток}
|ИЗ
|   РегистрНакопления.ВзаиморасчетыСКонтрагентами.Остатки(&Период, ) КАК Взаиморасчеты
|   {ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК СвойстваКонтрагентов
|       ПО СвойстваКонтрагентов.Объект = Взаиморасчеты.Контрагент
|       И СвойстваКонтрагентов.Свойство = &СвойствоОтветственный}
|{ГДЕ
|   Взаиморасчеты.Контрагент.*,
|   СвойстваКонтрагентов.Значение.* КАК ОтветственныйЗаПлатежи}
|{ИТОГИ И ГРУППИРОВАТЬ ПО
|   Контрагент.*,
|   ОтветственныйЗаПлатежи.*}";

После установки параметра &СвойствоОтветственный добавление измерения в код становится максимально прозрачным:


ОтчетОстатки.УниверсальныйОтчет.ПостроительОтчета.Параметры.Вставить(
    "СвойствоОтветственный", 
    ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("ОтветственныйЗаПлатежи")
);

ОтчетОстатки.УниверсальныйОтчет.ДобавитьИзмерениеСтроки("ОтветственныйЗаПлатежи");

Такой подход избавляет от громоздких динамических псевдонимов, упрощает отладку и предотвращает падение производительности СУБД, возникающее при автоматическом подключении десятков неиспользуемых свойств.

← На главную