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