При разработке отчетов, проведении документов и формировании выборок в 1С разработчики регулярно сталкиваются с задачей получения остатков на определенный момент времени или на конец дня. Часто возникает вопрос: почему платформа требует передачи объекта Граница со значением ВидГраницы.Включая и почему нельзя просто передать дату или прибавить к ней одну секунду? Разберем подробно, как устроен этот механизм изнутри, какие риски несет прибавление секунды и как правильно работать с виртуальными таблицами остатков.
Для понимания логики работы платформы проанализируем, как параметры виртуальной таблицы транслируются в реальные запросы к СУБД (SQL):
Период виртуальной таблицы остатков передать обычное значение типа Дата (например, КонецДня(ТекущаяДата()), то есть 31.01.2025 23:59:59), платформа 1С всегда формирует SQL-запрос со строгим неравенством: Период < @ПараметрДата. Это означает, что все записи и движения, совершенные ровно в 23:59:59, в выборку не попадут.Новый Граница(КонецДня(ТекущаяДата()), ВидГраницы.Включая), условие в SQL-запросе меняется на нестрогое неравенство: Период <= @ПараметрДата. В таком случае движения на последнюю секунду периода гарантированно учитываются при расчете итогов.В некоторых обучающих материалах встречается обходной прием: вместо создания объекта Граница разработчики просто добавляют к концу дня одну секунду (КонецДня(Дата) + 1), получая 00:00:00 следующего дня. Выясним причину, почему такой подход считается грубой ошибкой и приводит к скрытым багам в учетных системах:
00:00:00 первого числа каждого месяца). Если к дате 31.01.2025 23:59:59 прибавить одну секунду, запрос будет адресован на 01.02.2025 00:00:00. Платформа переключит алгоритм с выборки движений текущего месяца на использование итогов следующего месяца, что может кардинально изменить план выполнения запроса СУБД и повысить нагрузку на сервер.00:00:00 следующего числа. Прибавив секунду к концу текущего дня, запрос ошибочно захватит или отсечет движения, относящиеся уже к следующему дню.Граница в сочетании с МоментВремени обеспечивает точное разделение записей.Рассмотрим типовые примеры правильного получения остатков в программном коде 1С.
Пример 1. Получение остатков на конец дня или месяца:
Когда требуется рассчитать остаток на конец определенной даты с учетом всех движений, зарегистрированных в этот день:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&ГраницаОстатков, ) КАК ТоварыНаСкладахОстатки";
ДатаКонцаДня = КонецДня(ТекущаяДата());
Запрос.УстановитьПараметр("ГраницаОстатков", Новый Граница(ДатаКонцаДня, ВидГраницы.Включая));
РезультатЗапроса = Запрос.Выполнить();
Пример 2. Контроль остатков при проведении документа:
При оперативном или неоперативном проведении документа важно получить остатки строго до движений самого документа, чтобы не учитывать его собственные проводки:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиНоменклатуры.Номенклатура КАК Номенклатура,
| ОстаткиНоменклатуры.КоличествоОстаток КАК КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&ГраницаКонтроля, ) КАК ОстаткиНоменклатуры";
// Исключаем движения текущего документа
Запрос.УстановитьПараметр("ГраницаКонтроля", Новый Граница(ЭтотОбъект.МоментВремени(), ВидГраницы.Исключая));
РезультатЗапроса = Запрос.Выполнить();
Пример 3. Формирование печатной формы или акта сверки с учетом документа:
Если после записи и проведения документа требуется вывести остаток взаиморасчетов с контрагентом с учетом движений текущего документа, используем включающую границу по моменту времени:
ГраницаПечати = Новый Граница(СсылкаНаДокумент.МоментВремени(), ВидГраницы.Включая);
Запрос.УстановитьПараметр("ПериодГраница", ГраницаПечати);
При разработке отчетов на СКД разработчики часто сталкиваются с ситуацией, когда стандартный период отчета не захватывает движения на 23:59:59. Разберем, как это обрабатывается в СКД:
СтандартныйПериод), СКД на этапе компоновки макета автоматически трансформирует правую границу в значение типа Граница со свойством ВидГраницы.Включая.Дата, в выражении параметра схемы компоновки данных необходимо явно использовать функцию приведения к концу периода: КонецПериода(&КонецПериода, "ДЕНЬ"), либо формировать программную передачу параметра в коде перед выполнением компоновки:
ПараметрПериод = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("Период");
Если ПараметрПериод <> Неопределено Тогда
ПараметрПериод.Значение = Новый Граница(КонецДня(ВыбраннаяДата), ВидГраницы.Включая);
ПараметрПериод.Использование = Истина;
КонецЕсли;
Важно помнить о технических ограничениях объекта Граница:
Граница является сугубо программным объектом оперативной памяти (runtime-объектом). Его нельзя назначить типом реквизита в метаданных конфигурации или сохранить непосредственно в реквизит справочника или документа.Граница в стандартном окне настройки параметров запроса. Передавать границу в параметры запроса динамического списка возможно только программно через свойства компоновщика настроек.Таким образом, использование объекта Граница(Дата, ВидГраницы.Включая) — это не избыточность, а стандарт платформы 1С, гарантирующий математическую строгость запросов к СУБД и отсутствие ошибок при получении итогов на срезе времени.