При разработке отчетов на базе Системы компоновки данных (СКД) (поможет инструмент для ускорения разработки и тестирования схем СКД) программисты часто сталкиваются с неприятной особенностью: виртуальные таблицы (особенно таблица Остатки) не включают документы, записанные в последнюю секунду указанного периода. Это происходит потому, что тип данных Дата в 1С определяет момент времени с точностью до секунды, но не учитывает позицию документа внутри этой секунды. Рассмотрим подробнее, почему так происходит и какими способами можно добиться корректного отображения данных, включая границу периода.
Проанализируем ситуацию с точки зрения платформы 1С. Когда мы передаем в параметр виртуальной таблицы значение типа Дата (например, 31.12.2023 23:59:59), система интерпретирует это как момент времени. Все документы, имеющие ту же самую дату и время, технически могут располагаться «после» этого момента в иерархии позиций. В результате остатки рассчитываются «на начало» этой секунды, и данные за само окончание периода в отчет не попадают.
Для решения этой проблемы в платформе существует объект Граница, который позволяет явно указать, нужно ли включать документы этого момента в выборку (ВидГраницы.Включая) или нет (ВидГраницы.Исключая). Однако в СКД работа с этим объектом имеет свои нюансы, которые мы сейчас изучим.
Посмотрим на практическое наблюдение опытных разработчиков. Виртуальные таблицы Остатки и ОстаткиИОбороты ведут себя по-разному при обработке параметров периода. Выясним причину: таблица ОстаткиИОбороты изначально спроектирована для работы с интервалами, поэтому ее параметр КонецПериода по умолчанию обрабатывается более лояльно и зачастую захватывает данные границы без дополнительных манипуляций.
Если структура вашего отчета позволяет, попробуйте заменить таблицу Остатки на ОстаткиИОбороты. Это самый простой способ «обхода» проблемы без написания сложного кода.
Если нам необходимо использовать именно таблицу Остатки, наиболее правильным с точки зрения архитектуры 1С будет передача в параметр объекта Граница. Выполним это программно в модуле объекта отчета (в процедуре ПриКомпоновкеРезультата) или в модуле формы.
Рассмотрим пример кода, который устанавливает границу для параметра с именем Период (подобные задачи часто решает универсальная функция ПолучитьРезультатСКД()):
Параметр = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти(Новый ПараметрКомпоновкиДанных("Период"));
Если Параметр <> Неопределено Тогда
КонечнаяДата = КонецДня(ДатаОтчета);
Граница = Новый Граница(КонечнаяДата, ВидГраницы.Включая);
Параметр.Значение = Граница;
Параметр.Использование = Истина;
КонецЕсли;
Важное замечание: Чтобы этот код не вызывал ошибку «Несоответствие типов», необходимо в схеме компоновки данных (вкладка «Параметры») для соответствующего параметра снять флажок типа данных Дата. Если тип будет жестко ограничен датой, объект Граница туда просто не запишется.
Посмотрим, как можно решить задачу прямо в конструкторе СКД на закладке «Параметры». Это удобно, если вы не хотите лезть в программный код. Мы можем использовать встроенные функции языка выражений СКД, чтобы «сдвинуть» момент времени на одну секунду вперед.
Разберем по шагам создание выражения для параметра Период:
ДатаКонца (тип Дата), который пользователь будет видеть на форме.Период, который используется в запросе, в колонке «Выражение» напишите следующее:
ДобавитьКДате(КонецПериода(&ДатаКонца, "День"), "Секунда", 1)
Проанализируем ситуацию: добавление одной секунды к концу дня переносит расчет остатков на 00:00:00 следующего дня. Поскольку остатки на 00:00:00 следующего дня идентичны остаткам «после» последней секунды текущего дня, мы гарантированно получаем все данные, включая документы границы.
В современных конфигурациях, использующих Библиотеку стандартных подсистем (БСП), можно вызывать серверные функции прямо из выражений параметров СКД. Это позволяет возвращать объект Граница без написания кода в модуле отчета.
Пример выражения в параметре:
ОбщегоНазначенияКлиентСервер.ПолучитьГраницуПериода(КонецПериода(&ДатаКонца, "День"), ПредопределенноеЗначение("ВидГраницы.Включая"))
Если в вашей конфигурации нет БСП, вы можете создать свой общий модуль (например, РаботаСОтчетамиСервер) с флажком «Вызов сервера» и написать там простую функцию-обертку:
Функция ПолучитьГраницуВключая(Дата) Экспорт
Возврат Новый Граница(КонецДня(Дата), ВидГраницы.Включая);
КонецФункции
Затем в СКД используйте выражение: РаботаСОтчетамиСервер.ПолучитьГраницуВключая(&ДатаКонца).
Выясним еще один важный момент. При ручном написании запросов в СКД (не через конструктор виртуальных таблиц) важно правильно настроить закладку «Роли» у полей набора данных. Если поле является периодом, установите ему роль Период. Это поможет системе компоновки корректно обрабатывать временные срезы при генерации итогового запроса к базе данных.
Подведем итог: для гарантированного включения границы периода в отчет СКД используйте либо программную подстановку объекта Граница (не забыв отключить проверку типа в параметрах), либо метод «+1 секунда» через выражение в схеме. Эти методы избавят вас от расхождений данных в стандартных бухгалтерских отчетах и ваших собственных разработках.