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