Как получить остатки по регистру на момент времени, включая движения текущего документа?

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

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

Анализ проблемы: почему стандартный запрос не видит остатки

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


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

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

Проблема здесь заключается в том, что параметр Дата в виртуальной таблице Остатки интерпретируется платформой как «на начало указанного момента времени». Если документ записан в 12:00:00, то остатки на 12:00:00 не будут включать движения этого документа. Традиционно новички пытаются «извернуться», прибавляя к дате одну секунду, но у этого метода есть серьезные недостатки, которые мы разберем далее.

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

Самый правильный и эстетичный способ, рекомендуемый платформой 1С, — это использование специального объекта Граница. Этот объект позволяет явно указать системе, нужно ли включать записи, попадающие ровно на указанную временную точку.

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


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

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

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

Решение №2: Момент времени и его связь с Границей

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

Момент времени — это уникальная комбинация даты-времени и ссылки на документ. Если мы используем просто дату, система видит все документы этой секунды как «равные». Если же мы используем МоментВремени, система точно знает порядок следования документов внутри секунды.

Рассмотрим пример формирования границы через момент времени конкретного документа:


// Получаем остатки строго ПОСЛЕ проведения конкретного документа
МоментСразуПослеДокумента = Новый Граница(ДокументСсылка.МоментВремени(), ВидГраницы.Включая);
Запрос.УстановитьПараметр("Дата", МоментСразуПослеДокумента);

Этот метод считается «золотым стандартом» разработки. Он гарантирует, что вы получите остатки именно после транзакции конкретного документа, не захватывая лишних данных и не теряя текущие движения.

Почему прибавление секунды («+1с») — это плохая практика?

Часто в коде встречается конструкция Запрос.УстановитьПараметр("Дата", ТекущаяДата + 1); или использование функции в самом тексте запроса:


// В тексте запроса
ДОБАВИТЬКДАТЕ(&Дата, СЕКУНДА, 1)

Разберем по шагам, почему это решение может привести к ошибкам в промышленной эксплуатации:

  1. Проблема «конца дня»: Если ваш документ проведен в последнюю секунду суток (23:59:59), то прибавление секунды переносит расчет остатков на 00:00:00 следующего дня. Это может привести к тому, что запрос захватит документы будущего периода, которые уже успели ввести другие пользователи.
  2. Производительность: При использовании ДОБАВИТЬКДАТЕ непосредственно в теле запроса СУБД (например, SQL Server) может неэффективно использовать индексы итогов, так как дата становится вычисляемым выражением. Передача объекта Граница — более «легкий» способ для ядра платформы.
  3. Логическая чистота: Использование встроенных объектов платформы делает код более читаемым для других разработчиков и соответствует стандартам разработки фирмы «1С» (1С:Совместимо).

Использование таблицы «ОстаткиИОбороты»

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

У этой таблицы есть параметры НачалоПериода и КонецПериода. Если в качестве КонецПериода передать МоментВремени документа, платформа корректно обработает включение этого момента. Это избавляет от необходимости делать два разных запроса к разным таблицам.

Важные нюансы позиционирования на временной оси

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

Резюме и рекомендации

Мы выяснили, что наиболее профессиональным и безопасным способом получения остатков с учетом текущей секунды является использование объекта Граница. Посмотрим еще раз на краткий итог наших действий для успешного решения задачи:

  1. Всегда предпочитайте МоментВремени простой дате, если работаете с конкретным документом.
  2. Используйте Новый Граница(..., ВидГраницы.Включая) для захвата данных текущей секунды.
  3. Избегайте математических операций с датами (+1 секунда) в параметрах запросов, чтобы не столкнуться с переходом на следующий день.
  4. Передавайте готовый объект в параметр запроса, не вычисляйте дату внутри текста SQL.

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

← На главную