Как получить остатки на каждый месяц в 1С, если в некоторые периоды нет движений или остаток стал нулевым?

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

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

Выясняем причину: почему пропадают строки?

Проблема кроется в самой логике работы виртуальной таблицы ОстаткиИОбороты. Даже при использовании параметра МетодДополнения.ДвиженияИГраницыПериода, система гарантирует наличие записей только на начало и конец всего периода отчета, а также на даты фактических движений. Если по конкретному объекту аналитики (например, определенному счету или группе ИсточникКредитования) движений в феврале не было, то в выборке за февраль этого объекта не будет. Еще хуже ситуация становится, когда мы накладываем левое соединение на календарь, но забываем про «размножение» аналитики.

Решение 1: Формирование «сетки» через перекрестное соединение (Запрос)

Чтобы гарантировать наличие каждой группы в каждом месяце, мы должны сначала создать «скелет» или «сетку» отчета. Рассмотрим этот процесс по шагам.

Шаг 1. Создание таблицы периодов (Календаря). Мы можем сгенерировать таблицу дат динамически в запросе, используя соединение нескольких вспомогательных таблиц с цифрами. Это позволит получить последовательность месяцев от &НачПериода до &КонПериода.


ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(&НачПериода, МЕСЯЦ, Цифры4.Цифра * 1000 + Цифры3.Цифра * 100 + Цифры2.Цифра * 10 + Цифры1.Цифра) КАК Период
ПОМЕСТИТЬ ВТ_Календарь
ИЗ
    (ВЫБРАТЬ 0 КАК Цифра ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 3 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 4 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 5 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 6 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 7 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 8 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 9) КАК Цифры1
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ 0 КАК Цифра ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1 ... ВЫБРАТЬ 9) КАК Цифры2 ПО ИСТИНА
    ...
ГДЕ
    ДОБАВИТЬКДАТЕ(&НачПериода, МЕСЯЦ, Цифры4.Цифра * 1000 + Цифры3.Цифра * 100 + Цифры2.Цифра * 10 + Цифры1.Цифра) <= &КонПериода
;

Шаг 2. Получение уникальных аналитик. Нам нужны все группы, по которым потенциально могут быть остатки. Их можно выбрать из справочника или из того же регистра (но без привязки к периоду).


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ИсточникКредитования КАК Группа
ПОМЕСТИТЬ ВТ_Аналитика
ИЗ
    РегистрНакопления.ДенежныеСредства.Остатки(&НачПериода, )
;

Шаг 3. Создание «Сетки». Теперь соединим каждую группу с каждым месяцем. Это называется декартовым произведением. Мы получим строки для каждой группы на каждый месяц, даже если данных там еще нет.


ВЫБРАТЬ
    ВТ_Аналитика.Группа,
    ВТ_Календарь.Период
ПОМЕСТИТЬ ВТ_Сетка
ИЗ
    ВТ_Аналитика КАК ВТ_Аналитика
    СОЕДИНЕНИЕ ВТ_Календарь КАК ВТ_Календарь ПО ИСТИНА
;

Шаг 4. Соединение с данными и расчет остатка. Теперь мы соединяем нашу ВТ_Сетка с реальными данными регистра. Важный момент: чтобы «протянуть» остаток из прошлого месяца в текущий (где нет движений), нужно использовать метод расчета нарастающего итога: Начальный остаток на начало всего периода + Сумма оборотов по текущий месяц.


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

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

Если отчет строится на СКД, задачу можно решить гораздо элегантнее, не прибегая к сложным вложенным запросам и нарастающим итогам вручную. Разберем, как заставить СКД саму дополнять периоды.

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

Важные рекомендации и нюансы

Проанализируем несколько критических моментов, которые часто упускают из виду:

Рассмотренные методы позволяют создавать надежные отчеты, которые не «теряют» аналитику при обнулении сумм, что критически важно для финансового и управленческого учета.

← На главную