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