Как получить остатки и обороты регистра накопления в разрезе родителя группы

Программист 1С v8.3 (Управляемые формы) Управленческий учет Финансы и профессиональные услуги
← На главную

При разработке отчетов на платформе 1С:Предприятие 8 программисты часто сталкиваются с необходимостью агрегации данных не только по конкретным элементам справочников, но и по их родителям (группам). Если с оборотами (приходом и расходом) проблем обычно не возникает — их можно просто просуммировать, — то с остатками дело обстоит иначе. Простая группировка по полю Родитель в запросе часто приводит к нулевым или некорректным значениям в колонках начального и конечного остатков.

В этой статье мы подробно разберем, почему так происходит, и рассмотрим несколько способов решения этой задачи: от ручной корректировки запроса до использования механизмов Системы компоновки данных (СКД).

Почему стандартная группировка не работает для остатков

Для начала проанализируем, как работает виртуальная таблица ОстаткиИОбороты. Платформа 1С оптимизирует запросы к этой таблице так, чтобы расчет итогов происходил автоматически по всем измерениям, указанным в параметрах таблицы. Однако, как только мы пытаемся заменить измерение (например, ПроектИнвестиции) на его реквизит (ПроектИнвестиции.Родитель), система перестает воспринимать это поле как измерение регистра.

Важный нюанс: Начальный остаток в виртуальной таблице — это не просто сумма. Это значение на определенный момент времени (границу периода). Если мы просто сгруппируем записи по родителю, используя СУММА(СуммаНачальныйОстаток), мы можем получить правильный результат только в том случае, если по всем дочерним элементам есть движения. Если же по какому-то элементу движений в выбранном периоде не было, он может вообще не попасть в выборку или исказить итоги при использовании периодичности.

Решение 1: Использование формул для расчета остатков в запросе

Один из самых быстрых способов получить корректный начальный остаток при группировке по родителю — это вычислить его математически на основе конечного остатка и оборотов. Мы знаем базовое бухгалтерское равенство: НачальныйОстаток = КонечныйОстаток - Приход + Расход.

Рассмотрим пример запроса, в котором мы применяем эту логику. Допустим, нам нужно сгруппировать данные по полю ПроектИнвестиции.Родитель. Проанализируем следующий подход:


ВЫБРАТЬ
    Результаты.ПроектИнвестицииРодитель КАК ПроектИнвестицииРодитель,
    СУММА(Результаты.СуммаНачальныйОстатокРасчетный) КАК СуммаНачальныйОстаток,
    СУММА(Результаты.СуммаПриход) КАК СуммаПриход,
    СУММА(Результаты.СуммаРасход) КАК СуммаРасход,
    СУММА(Результаты.СуммаКонечныйОстаток) КАК СуммаКонечныйОстаток
ИЗ
    (ВЫБРАТЬ
        РезультатыИнвестиций.ПроектИнвестиции.Родитель КАК ПроектИнвестицииРодитель,
        ВЫБОР
            КОГДА РезультатыИнвестиций.СуммаНачальныйОстаток <> 0
                ТОГДА РезультатыИнвестиций.СуммаНачальныйОстаток
            ИНАЧЕ ЕСТЬNULL(РезультатыИнвестиций.СуммаКонечныйОстаток, 0) - ЕСТЬNULL(РезультатыИнвестиций.СуммаПриход, 0) + ЕСТЬNULL(РезультатыИнвестиций.СуммаРасход, 0)
        КОНЕЦ КАК СуммаНачальныйОстатокРасчетный,
        РезультатыИнвестиций.СуммаПриход КАК СуммаПриход,
        РезультатыИнвестиций.СуммаРасход КАК СуммаРасход,
        РезультатыИнвестиций.СуммаКонечныйОстаток КАК СуммаКонечныйОстаток
    ИЗ
        РегистрНакопления.РезультатыИнвестиций.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , ПроектИнвестиции В ИЕРАРХИИ(&ПроектИнвестиции)) КАК РезультатыИнвестиций) КАК Результаты

СГРУППИРОВАТЬ ПО
    Результаты.ПроектИнвестицииРодитель

В данном примере мы используем вложенный запрос, где для каждой строки вычисляем "расчетный" начальный остаток. Это позволяет избежать проблемы "пустых" остатков при агрегации по иерархии на уровне СУБД.

Решение 2: Использование СКД (Система компоновки данных)

Если вы разрабатываете отчет, наиболее правильным и надежным методом будет использование СКД. Система компоновки данных специально спроектирована для работы с остатками и иерархией. Выясним, какие настройки для этого необходимы:

  1. Роли полей: В наборе данных запроса для полей остатков необходимо правильно настроить роли. Для поля СуммаНачальныйОстаток установите тип "Начальный остаток", а для СуммаКонечныйОстаток — "Конечный остаток". Укажите имя группы и свяжите их с соответствующим полем периода.
  2. Иерархическая группировка: В настройках отчета (вкладка "Настройки") добавьте группировку не просто по полю ПроектИнвестиции, а выберите тип Иерархия или Только иерархия.
  3. Автоматический расчет: При использовании ролей СКД сама поймет, как нужно рассчитывать остатки для родительских записей. Она не будет просто суммировать их, а возьмет срез на начало и конец периода для всей группы элементов в целом.

Проанализируем ситуацию: использование СКД избавляет нас от необходимости писать сложные вложенные запросы и гарантирует точность данных при любых настройках периодичности (день, месяц, регистратор).

Решение 3: Добавление измерения в регистр

Если задача получения данных в разрезе родителей стоит очень остро и выполняется часто (например, в высоконагруженных динамических списках или оперативных панелях), стоит рассмотреть изменение структуры самого регистра.

Рассмотрим шаги по реализации этого метода:

  1. Добавьте в регистр накопления новое измерение, например, ПроектИнвестицииРодитель.
  2. При проведении документов заполняйте это измерение значением ПроектИнвестиции.Родитель.
  3. В запросе обращайтесь напрямую к этому измерению в виртуальной таблице ОстаткиИОбороты.

Преимущества: Скорость работы запроса увеличится в разы, так как СУБД будет использовать готовые итоги по этому измерению. Недостатки: Увеличение размера базы данных и необходимость перепроведения документов для заполнения нового измерения в исторических данных.

Решение 4: Расчет нарастающим итогом

В некоторых случаях, когда нужно вывести остатки по иерархии в динамике (например, по дням), можно использовать метод нарастающего итога. Посмотрим, как это работает:

Сначала мы получаем обороты по родителям за каждый период. Затем соединяем таблицу оборотов саму с собой по условию Таблица1.Период >= Таблица2.Период. Суммируя обороты "прошлых" периодов и прибавляя к ним начальный остаток на самую первую дату отчета, мы получаем актуальный остаток на любую точку времени.

Этот метод технически сложнее в реализации на языке запросов 1С, но он дает максимальную гибкость, если стандартные виртуальные таблицы не подходят под требования бизнес-логики.

Итоги и рекомендации

Подводя итог, можно сказать, что выбор метода зависит от конкретной задачи:

Помните, что при работе с остатками по иерархии важно всегда проверять результаты на наличие "пустых" периодов, так как отсутствие движений по дочерним элементам может скрывать остатки по группе в целом, если фильтрация в запросе настроена недостаточно точно.

← На главную