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