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

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

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

Решение 1. Использование конструкции ПЕРИОДАМИ и обхода по группировкам

Язык запросов 1С предоставляет механизм автоматического дополнения периодов в блоке расчета итогов. Для этого используется конструкция ПЕРИОДАМИ в секции ИТОГИ ПО. Проанализируем базовый вариант запроса и правильный порядок его обработки во встроенном языке.

Посмотрим на пример запроса с дополнением дат:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Взаиморасчеты.Период КАК Период,
    |	Взаиморасчеты.СуммаВзаиморасчетовКонечныйОстаток КАК КонечныйОстаток
    |ИЗ
    |	РегистрНакопления.ВзаиморасчетыСКонтрагентамиПоДокументамРасчетов.ОстаткиИОбороты(
    |			&НачалоПериода,
    |			&КонецПериода,
    |			День,
    |			ДвиженияИГраницыПериода,
    |			ДокументРасчетовСКонтрагентом = &ДокументРасчетовСКонтрагентом) КАК Взаиморасчеты
    |ИТОГИ
    |	СУММА(КонечныйОстаток)
    |ПО
    |	ОБЩИЕ,
    |	Период ПЕРИОДАМИ(ДЕНЬ, &НачалоПериода, &КонецПериода)";

Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ПолеВводаДата.Значение));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("ДокументРасчетовСКонтрагентом", ВыбранныйДокумент);

РезультатЗапроса = Запрос.Выполнить();

Обратим особое внимание на ключевые особенности построения этого запроса и типичные ошибки:

  1. Отбор в параметрах виртуальной таблицы, а не в ГДЕ: Условие по аналитике ДокументРасчетовСКонтрагентом обязательно должно находиться в 5-м параметре виртуальной таблицы. Если вынести условие в блок ГДЕ, платформа сначала рассчитает остатки по всей таблице регистра за весь период, а затем применит фильтр, что приведет к фатальному падению производительности и ошибкам в расчете остатков.
  2. Метод дополнения периода: В 4-м параметре таблицы рекомендуется указывать ДвиженияИГраницыПериода. Это гарантирует, что границы интервала будут включены в расчет.
  3. Время границы конца периода: Если передать в параметр &КонецПериода значение через НачалоДня() (00:00:00), движения последнего дня не попадут в выборку. Следует использовать КонецДня().

Теперь рассмотрим, как правильно обойти выборку. Если вызвать стандартный метод Выбрать() без параметров, результат вернет плоскую таблицу без дополненных дней. Для вывода дополненной шкалы времени необходимо обращаться к группировке с параметром "Все":


ВыборкаПериод = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "Все");
ТекущийОстаток = 0;

Пока ВыборкаПериод.Следующий() Цикл
    // Если на дату движений не было, агрегатная сумма вернет NULL или 0.
    // Для сохранения остатка предыдущего дня выполняем проверку значения:
    Если ВыборкаПериод.КонечныйОстаток <> NULL И ВыборкаПериод.КонечныйОстаток <> 0 Тогда
        ТекущийОстаток = ВыборкаПериод.КонечныйОстаток;
    КонецЕсли;
    
    Сообщить("Дата: " + Формат(ВыборкаПериод.Период, "ДФ=dd.MM.yyyy") + " | Остаток: " + ТекущийОстаток);
КонецЦикла;

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

Решение 2. Формирование шкалы дат и расчет нарастающего итога в запросе

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

Разберем по шагам логику такого запроса:

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

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

Этот подход исключает необходимость использования конструкции ИТОГИ и позволяет передавать результат напрямую в другие процедуры обработки данных.

Решение 3. Программный вывод через Систему компоновки данных (СКД)

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

Рассмотрим порядок настройки схемы компоновки:

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