При разработке собственных отчетов на базе типового механизма Универсальный отчет (использующего объект ПостроительОтчета) разработчики часто сталкиваются с ситуацией: в текст запроса добавляется ссылка на документ, поле выбирается в настройках группировок, однако отчет упорно выводит только вышестоящие уровни (например, номенклатуру), игнорируя детальные записи или документы движения. Разберем по шагам, почему возникает эта ошибка и как правильно настроить текст запроса, измерения и отбор по периоду.
Механизм ПостроительОтчета использует специальные секции расширения, заключенные в фигурные скобки: {ВЫБРАТЬ ...}, {ГДЕ ...}, {ИТОГИ ПО ...} и {УПОРЯДОЧИТЬ ПО ...}. Если поле присутствует в основном теле запроса, но не описано должным образом в секциях расширения или имеет расхождения в псевдонимах, построитель отчета не сможет предоставить его пользователю в качестве доступного поля или измерения.
Посмотрим на пример некорректного текста запроса, где поле документа объявлено с псевдонимом, но не согласовано с блоками расширения построителя:
ТекстЗапроса =
"ВЫБРАТЬ
СписаниеТоваровТовары.Ссылка.Организация,
СписаниеТоваровТовары.Ссылка.Подразделение,
СписаниеТоваровТовары.Ссылка.Склад,
СписаниеТоваровТовары.Ссылка КАК ДокументДвижения,
СписаниеТоваровТовары.Номенклатура КАК Номенклатура,
СписаниеТоваровТовары.Количество КАК Количество
{ВЫБРАТЬ
Количество}
ИЗ
Документ.СписаниеТоваров.Товары КАК СписаниеТоваровТовары
ГДЕ
СписаниеТоваровТовары.Ссылка.Проведен
{ГДЕ
СписаниеТоваровТовары.Ссылка.Организация.*,
СписаниеТоваровТовары.Ссылка.Подразделение.*,
СписаниеТоваровТовары.Ссылка.Склад.*,
СписаниеТоваровТовары.Ссылка.*}
ИТОГИ
СУММА(Количество)
ПО
ОБЩИЕ
{ИТОГИ ПО
Организация.*,
Подразделение.*,
Склад.*,
Номенклатура.*,
ДокументДвижения.*}";
В приведенном фрагменте допущены следующие ключевые ошибки:
{ВЫБРАТЬ} объявлено только поле Количество. Поля ДокументДвижения.* и Номенклатура.* отсутствуют, что ограничивает возможность их гибкого вывода в детальные записи и колонки.{ИТОГИ ПО} перечислены поля Организация.*, Подразделение.*, Склад.*, которые в блоке ВЫБРАТЬ не имеют явных псевдонимов с такими же именами (они выбраны через обращение к реквизитам шапки без КАК Организация). Построитель отчета требует точного соответствия псевдонимов.Рассмотрим правильный вариант формирования запроса для построителя. Обязательно вынесем все необходимые группировочные поля в секцию {ВЫБРАТЬ} и приведем в соответствие имена в секции {ИТОГИ ПО}.
ТекстЗапроса =
"ВЫБРАТЬ
СписаниеТоваровТовары.Ссылка КАК ДокументДвижения,
СписаниеТоваровТовары.Количество КАК Количество,
СписаниеТоваровТовары.Номенклатура КАК Номенклатура
{ВЫБРАТЬ
ДокументДвижения.*,
Номенклатура.*,
Количество}
ИЗ
Документ.СписаниеТоваров.Товары КАК СписаниеТоваровТовары
ГДЕ
СписаниеТоваровТовары.Ссылка.Проведен
{ГДЕ
СписаниеТоваровТовары.Ссылка.Склад.*,
СписаниеТоваровТовары.Ссылка.*}
ИТОГИ
СУММА(Количество)
ПО
ОБЩИЕ
{ИТОГИ ПО
Номенклатура.*,
ДокументДвижения.*}";
УниверсальныйОтчет.ПостроительОтчета.Текст = ТекстЗапроса;
Чтобы программно добавить группировку строк по документу при инициализации отчета, используем стандартные методы Универсального отчета:
// Добавляем группировки строк
УниверсальныйОтчет.ДобавитьИзмерениеСтроки("Номенклатура");
УниверсальныйОтчет.ДобавитьИзмерениеСтроки("ДокументДвижения");
// При необходимости включаем вывод детальных записей
УниверсальныйОтчет.ВыводитьДетальныеЗаписи = Истина;
Частая причина, по которой изменения в коде не отображаются на форме — сохранение старых пользовательских настроек отчета в системном хранилище. Построитель отчета при открытии формы восстанавливает предыдущую структуру группировок, игнорируя новые поля из запроса.
Для устранения этой проблемы выполним следующие действия:
мВосстанавливатьНастройкиПриОткрытии = Ложь; или переинициализировав макет:</li
УниверсальныйОтчет.ПостроительОтчета.Макет = Неопределено;
УниверсальныйОтчет.УстановитьНачальныеНастройки(Ложь);
Проанализируем вторую типичную проблему: указание периода на форме отчета не влияет на выборку данных. Добавление поля в секцию {ГДЕ СписаниеТоваровТовары.Ссылка.Дата} лишь делает реквизит доступным для ручного отбора в таблице настроек, но не связывает его автоматически с полями ввода ДатаНач и ДатаКон.
Чтобы период отчета работал корректно, применим один из двух подходов:
Вариант А: Передача периода через параметры запроса
В секцию ГДЕ основного запроса добавим явное условие с параметрами:
ГДЕ
СписаниеТоваровТовары.Ссылка.Проведен
И СписаниеТоваровТовары.Ссылка.Дата МЕЖДУ &ДатаНач И &ДатаКон
Перед формированием отчета передадим значения параметров в построитель:
ГраницаКонцаДня = ?(ЗначениеЗаполнено(УниверсальныйОтчет.ДатаКон), КонецДня(УниверсальныйОтчет.ДатаКон), '39991231235959');
ГраницаНачалаДня = ?(ЗначениеЗаполнено(УниверсальныйОтчет.ДатаНач), НачалоДня(УниверсальныйОтчет.ДатаНач), '00010101000000');
УниверсальныйОтчет.ПостроительОтчета.Параметры.Вставить("ДатаНач", ГраницаНачалаДня);
УниверсальныйОтчет.ПостроительОтчета.Параметры.Вставить("ДатаКон", ГраницаКонцаДня);
Вариант Б: Программное заполнение отбора построителя
Если условие формируется динамически через {ГДЕ СписаниеТоваровТовары.Ссылка.*}, программно настроим элемент отбора по дате:
Если ЗначениеЗаполнено(УниверсальныйОтчет.ДатаНач) ИЛИ ЗначениеЗаполнено(УниверсальныйОтчет.ДатаКон) Тогда
ОтборПоДате = УниверсальныйОтчет.ПостроительОтчета.Отбор["Ссылка.Дата"];
Если ОтборПоДате <> Неопределено Тогда
ОтборПоДате.Использование = Истина;
ОтборПоДате.ВидСравнения = ВидСравнения.ИнтервалВключаяГраницы;
ОтборПоДате.ЗначениеС = НачалоДня(УниверсальныйОтчет.ДатаНач);
ОтборПоДате.ЗначениеПо = КонецДня(УниверсальныйОтчет.ДатаКон);
КонецЕсли;
КонецЕсли;
Обращение напрямую к табличным частям документов (Документ.СписаниеТоваров.Товары) для получения движений за период является неоптимальным с точки зрения производительности. Если конфигурация использует регистры накопления, рекомендуется строить отчет по виртуальной таблице оборотов соответствующего регистра (например, РегистрНакопления.ТоварыНаСкладах.Обороты(&ДатаНач, &ДатаКон, Авто, ...)). В таком случае документ движения автоматически доступен через системное поле Регистратор, а фильтрация по периоду выполняется на уровне СУБД с использованием индексов таблицы итогов.