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

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

При разработке отчетов и обработок на платформе 1С программисты часто сталкиваются с задачей выгрузки актуального остатка или дневного оборота денежных средств. Распространенной ошибкой является попытка рассчитать конечный остаток путем сплошного обхода и вычитания сумм из виртуальной таблицы Обороты с детализацией по каждому документ-регистратору.

В этой статье мы подробно разберем, чем отличаются таблицы Остатки и Обороты, как правильно передавать параметры виртуальных таблиц и оптимизировать запрос для получения точных данных.

Различие задач: Оборот за день и Накопленный остаток

Перед написанием запроса необходимо четко определить бизнес-требование:

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

Рассмотрим реализацию обеих задач по шагам.

Вариант 1. Получение накопленного остатка денежных средств

Для получения итогового остатка необходимо задействовать виртуальную таблицу Остатки регистра накопления. Запрос по оборотному регистру для этих целей не подходит, так как платформе придется суммировать все движения с самого начала ведения учета, что создает огромную нагрузку на СУБД.

Проанализируем пример корректного запроса для получения остатка на конец текущего дня:


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

// Для точного включения всех документов текущего дня используем объект Граница
КонецТекущегоДня = КонецДня(ТекущаяДата());
ГраницаПериода = Новый Граница(КонецТекущегоДня, ВидГраницы.Включая);

Запрос.УстановитьПараметр("Период", ГраницаПериода);

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

Если Выборка.Следующий() Тогда
    ЭлементыФормы.КассоваяКнига.Заголовок = Выборка.СуммаОстаток;
КонецЕсли;

Обратим внимание на технические детали данного кода:

  1. Использование объекта Граница: передача простой даты вида КонецДня(ТекущаяДата()) может исключить из расчета документы, проведенные ровно в последнюю секунду дня (23:59:59). Использование объекта Граница с типом ВидГраницы.Включая гарантирует учет всех операций текущего дня.
  2. Обработка NULL: функция ЕСТЬNULL защищает от получения пустого значения, если в регистре нет остатков.
  3. Отказ от цикла: поскольку запрос возвращает агрегированный остаток в одной строке, обход выборки в цикле Пока Выборка.Следующий() не требуется.

Вариант 2. Расчет чистых оборотов (приход и расход) за день

Если задача состоит в том, чтобы выдать разницу между приходом и расходом за текущие сутки, используем виртуальную таблицу Обороты. Параметры дат следует передавать строго в скобках самой таблицы.

Посмотрим на пример запроса для расчета оборота за день:


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

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

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

Если Выборка.Следующий() Тогда
    ЭлементыФормы.КассоваяКнига.Заголовок = Выборка.ДневнойРезультат;
КонецЕсли;

Типичные ошибки при работе с виртуальными таблицами

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

  1. Избыточная периодичность Регистратор: если третьим параметром виртуальной таблицы Обороты передать значение Регистратор, платформа детализирует итоги по каждому документу. Вместо одной итоговой строки сформируется массив строк, а результат в цикле будет постоянно перезаписываться значением последнего документа.
  2. Фильтрация в секции ГДЕ: при использовании отбора по периоду в секции ГДЕ платформа сначала прочитает всю таблицу движений за всё время, и лишь затем отфильтрует её. Передача дат в параметры виртуальной таблицы Обороты(&НачалоПериода, &КонецПериода) заставляет СУБД рассчитывать итоги только за указанный интервал.
  3. Ограничения типов регистров: виртуальная таблица Остатки доступна только для регистров накопления с видом «Остатки». Если регистр имеет вид «Обороты», получить накопленный остаток штатной виртуальной таблицей невозможно.
← На главную