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