Как получить остатки в 1С на конец дня 23:59:59, если документы этого времени не попадают в запрос

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

Проблема получения остатков на «самую последнюю секунду» дня (23:59:59) является классической для платформы 1С. Часто программисты сталкиваются с ситуацией, когда документ, созданный в 23:59:59, упорно игнорируется виртуальными таблицами регистров накопления, даже если в параметрах запроса указан конец дня и тип границы Включая. В этой статье мы подробно разберем, почему это происходит, и как правильно настроить запрос, чтобы данные учитывались корректно.

Анализируем техническую природу проблемы

Разберем ситуацию: в системе есть документ начисления (например, аренды), который делает движения в регистр накопления в последнюю секунду месяца — 28.02.2021 23:59:59. При формировании запроса к виртуальной таблице ОстаткиИОбороты или Остатки программист передает дату конца дня. Однако документ «выпадает» из выборки. Почему так происходит?

Во-первых, важно понимать разницу между типом Дата и позицией документа на оси времени. В 1С документы, имеющие одинаковое время (вплоть до секунды), выстраиваются в строгую последовательность. Эта последовательность определяется моментом времени, который включает в себя не только время, но и ссылку на сам документ. Если мы передаем в запрос просто дату со временем 23:59:59, платформа может интерпретировать эту точку как «начало» этой секунды или как точку, после которой в этой же секунде могут существовать другие записи.

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

Решение 1: Правильное использование объекта Граница

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

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


ПараметрыГраницы = Новый Массив(2);
ПараметрыГраницы[0] = КонецДня(МоментВремени); // Здесь МоментВремени — это Дата
ПараметрыГраницы[1] = ВидГраницы.Включая;
Граница = Новый(Тип("Граница"), ПараметрыГраницы);

Запрос.УстановитьПараметр("МоментНачисленияПени", Граница);

Если такой подход не работает, это означает, что документы внутри секунды 23:59:59 расположены «после» того логического момента, который сформировала Граница по дате. Чтобы решить эту проблему, попробуем использовать МоментВремени конкретного документа, если расчет привязан к нему, либо использовать специальное смещение.

Решение 2: Смещение границы на начало следующего дня

Это один из самых надежных «практических» методов. Вместо того чтобы пытаться поймать последнюю секунду текущего дня, мы устанавливаем границу на начало следующего дня, но с видом границы Исключая. Либо просто используем дату начала следующего дня без объекта граница (по умолчанию в запросах для параметров конца периода используется вид границы Исключая).

Разберем, как это реализовать в коде:


// Вместо КонецДня(НужнаяДата)
НужнаяДата = '20210228235959';
ГраницаСледующегоДня = НачалоДня(НужнаяДата + 86400); // Получаем 01.03.2021 00:00:00

// В запросе используем эту дату как параметр
Запрос.УстановитьПараметр("КонецПериода", ГраницаСледующегоДня);

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

Решение 3: Особенности таблицы ОстаткиИОбороты и фильтрация

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


ИЗ
 РегистрНакопления.АР_ВзаиморасчетыПоАренде.ОстаткиИОбороты(
 &НачалоПериода,
 &МоментНачисления,
 Запись,
 ,
 ДоговорКонтрагента = &ДоговорКонтрагента
 И НЕ Депозит
 И НЕ Пени) КАК АР_ВзаиморасчетыПоАрендеОстатки

Выясним причину возможной ошибки: если документ начисления в 23:59:59 сам по себе не соответствует условиям фильтра (например, у него стоит признак "Пени"), но при этом он должен влиять на остаток по другим измерениям, то в таблице ОстаткиИОбороты может возникнуть «провал». При периодичности Запись система анализирует движения. Если движений, подходящих под фильтр, в эту секунду нет, конечный остаток может не рассчитаться так, как вы ожидаете.

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

Проблема условий соединения в запросе

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


ПО (АР_ВзаиморасчетыПоАрендеОстатки.Период > КОНЕЦПЕРИОДА(ДатаДоговора.ДатаЗаключенияДоговора, МЕСЯЦ))

Проанализируем ситуацию: функция КОНЕЦПЕРИОДА(..., МЕСЯЦ) возвращает дату с временем 23:59:59. Если период документа в регистре также равен 23:59:59 того же дня, то условие «строго больше» (>) отсечет этот документ. Это критическая ошибка проектирования запроса. В 1С сравнение дат происходит с точностью до секунды. Если две даты равны 23:59:59, то одна не может быть «больше» другой.

Рекомендация: Всегда проверяйте операторы сравнения при работе с датами конца периода. Вместо > используйте >= или приводите сравниваемые величины к началу дня, если время не имеет значения для логики расчета.

Итоговый чек-лист для исправления проблемы

  1. Используйте Новый Граница(КонецДня(НужнаяДата), ВидГраницы.Включая) для передачи в параметры виртуальной таблицы.
  2. Если первый пункт не помог, попробуйте передать НачалоДня(НужнаяДата + 86400) (следующий день) в качестве границы.
  3. Проверьте, не используется ли в ГДЕ или в условиях соединения оператор > (строго больше) по отношению к дате документа.
  4. Убедитесь, что в виртуальной таблице ОстаткиИОбороты фильтры не отсекают сам документ, который должен зафиксировать остаток на конец периода.
  5. Если задача позволяет, замените ОстаткиИОбороты на таблицу Остатки — она работает с границами времени более предсказуемо.

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

← На главную