Как правильно получить остатки на конец периода в отчете СКД, чтобы учесть документы в последней секунде дня?

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

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

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

Почему простая передача даты 23:59:59 не работает?

Разберем природу типа Дата в 1С:Предприятие. Дата содержит время с точностью до секунды. Однако в рамках одной секунды может существовать множество событий (документов), каждое из которых имеет свой уникальный Момент времени. Момент времени — это комбинация даты, времени и ссылки на объект, что позволяет системе однозначно выстроить последовательность документов в БД.

Когда мы передаем в виртуальную таблицу остатков параметр &КонецПериода со значением 31.12.2023 23:59:59, платформа интерпретирует это как запрос остатков «на начало» указанной секунды. В результате все движения, совершенные в эту самую секунду, игнорируются. Наша задача — заставить СКД учитывать все движения включая последнюю секунду.

Решение 1: Программная установка объекта Граница

Наиболее точный и «каноничный» способ — это использование объекта Граница. Этот объект позволяет явно указать системе, нужно ли включать движения, попадающие ровно на указанный момент. Мы можем передать в качестве параметра виртуальной таблицы не просто дату, а объект Новый Граница(Дата, ВидГраницы.Включая).

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

Пошаговый алгоритм реализации:

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

Проанализируем пример кода:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // 1. Отключаем стандартную обработку, если планируем выводить отчет полностью программно, 
    // либо оставляем Истина, если просто меняем параметры.
    
    // 2. Находим нужный нам параметр в настройках компоновщика
    ПараметрКонецПериода = КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("КонецПериода"));
    ПараметрПользователя = КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ПериодДата"));
    
    Если ПараметрКонецПериода <> Неопределено И ПараметрПользователя <> Неопределено Тогда
        // Формируем границу на конец дня выбранной пользователем даты
        КонечнаяДата = КонецДня(ПараметрПользователя.Значение);
        ПараметрКонецПериода.Значение = Новый Граница(КонечнаяДата, ВидГраницы.Включая);
        ПараметрКонецПериода.Использование = Истина;
    КонецЕсли;

КонецПроцедуры

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

Решение 2: Использование виртуальной таблицы «Остатки и обороты»

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

Рассмотрим, как настроить эту таблицу для получения корректного конечного остатка:

  1. В конструкторе запроса выберем таблицу РегистрНакопления.ИмяРегистра.ОстаткиИОбороты.
  2. В параметрах таблицы укажем период (начало и конец).
  3. На закладке «Настройки» в СКД для этого набора данных или в параметрах виртуальной таблицы установим свойство Метод дополнения в значение ДвиженияИГраницыПериода.

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

Решение 3: Манипуляции с «лишней секундой» (Плюс 1 секунда)

Это популярный «хак», который часто встречается в старых разработках. Суть проста: если 23:59:59 не включает документы, давайте возьмем начало следующего дня — 00:00:00.

В выражении параметра СКД на закладке «Параметры» мы можем написать следующее:

ДобавитьКДате(КонецПериода(&КонецПериода, "ДЕНЬ"), "СЕКУНДА", 1)

Рассмотрим плюсы и минусы этого подхода:

Выясним причину, почему это происходит. Таблица остатков на 00:00:00 следующего дня фактически показывает состояние «на начало дня». Таким образом, документы текущего дня (старого периода) учтены, но грань между периодами становится размытой. Мы рекомендуем использовать этот метод с осторожностью.

Решение 4: Современный подход через функции БСП

Если вы работаете в конфигурации на базе Библиотеки стандартных подсистем (БСП), например, в 1С:ERP, КА или БП 3.0, у вас есть возможность использовать готовые серверные функции прямо в выражениях СКД. Это позволяет получить объект Граница без написания кода в модуле отчета.

Посмотрим, как это выглядит. В поле «Выражение» для параметра &КонецПериода на закладке «Параметры» можно прописать вызов функции общего модуля:

ОбщегоНазначенияКлиентСервер.ПолучитьГраницу(КонецПериода(&КонецПериода, "ДЕНЬ"), ВидГраницы.Включая)

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

Важные замечания по настройке СКД

Проанализируем еще один нюанс: параметр СтандартныйПериод. Часто в отчетах используется один параметр типа СтандартныйПериод вместо двух отдельных дат. В этом случае СКД автоматически создает два внутренних значения: &Период.ДатаНачала и &Период.ДатаОкончания.

Если вы используете &Период.ДатаОкончания напрямую в параметрах виртуальной таблицы, обязательно проверьте настройки на вкладке «Параметры» СКД. По умолчанию 1С может подставлять дату окончания периода как начало последнего дня, если не указано иное. Всегда используйте конструкцию КонецПериода(&Период.ДатаОкончания, "ДЕНЬ") в поле выражения, чтобы гарантированно получить время 23:59:59, а затем преобразуйте её в границу одним из вышеописанных способов.

Итоги

Мы рассмотрели несколько стратегий получения остатков. Подведем итоги выбора лучшего решения:

  1. Объект Граница (программно): Самый надежный и универсальный метод для любой конфигурации.
  2. Таблица ОстаткиИОбороты: Лучший выбор, если нужно обойтись без программирования и требуются обороты за период.
  3. Функции БСП: Оптимальный вариант для современных типовых решений (ERP, ЗУП, БП).

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

← На главную