Как устранить расхождение остатков в отчетах 1С на границе периодов

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

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

Выясняем причину: почему «теряются» документы?

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

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

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

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

У объекта Граница есть два варианта вида:

  1. ВидГраницы.Включая — все движения, совершенные в эту секунду, попадут в результат.
  2. ВидГраницы.Исключая — движения этой секунды учитываться не будут.

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


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

    // Далее стандартный вывод отчета
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Решение 2: Использование выражений в параметрах СКД

Если вы не хотите писать программный код, можно воспользоваться механизмом выражений СКД на закладке Параметры. Посмотрим на этот вариант подробнее. Мы можем манипулировать датой, прибавляя или отнимая секунды, чтобы «сдвинуть» точку расчета остатка.

Разберем ситуацию: пользователь вводит дату конца 31.01.2021 23:59:59. Чтобы включить движения этой секунды, нам фактически нужно получить остаток на начало следующего дня (01.02.2021 00:00:00).

В схеме компоновки данных для параметра КонецПериода (или вашего внутреннего параметра запроса) можно прописать следующее выражение:

ДобавитьКДате(КонецПериода(&ПользовательскаяДатаКонца, "День"), "Секунда", 1)

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

Решение 3: Смещение на секунду назад для начального остатка

Проанализируем обратную ситуацию из сообщения автора. Экономист задает начало периода 31.01.2021 23:59:59. В этом случае документ, проведенный в 23:59:59, не попадает в Начальный остаток, так как остаток берется «на начало секунды». Если бизнес-логика требует, чтобы этот документ уже был учтен, нам нужно получить остаток на 1 секунду позже или использовать объект Граница.

В СКД это можно решить через проверку условия в выражении параметра:


Выбор 
    Когда Час(&ДатаН) = 23 И Минута(&ДатаН) = 59 И Секунда(&ДатаН) = 59 
    Тогда ДобавитьКДате(&ДатаН, "Секунда", 1) 
    Иначе &ДатаН 
Конец

Хотя такой подход выглядит как «костыль», он позволяет быстро решить проблему визуального несовпадения данных без изменения логики проведения документов.

Решение 4: Использование стандартного периода

Наилучшей практикой в СКД считается использование одного параметра с типом СтандартныйПериод. Когда пользователь выбирает период через стандартный диалог (например, «Январь»), СКД автоматически устанавливает дату начала на 01.01.2021 00:00:00 и дату окончания на 31.01.2021 23:59:59.

Чтобы виртуальные таблицы работали корректно, в запросе СКД лучше использовать не сам СтандартныйПериод, а скрытые параметры, которые вычисляются на его основе:

Важно помнить, что при работе с виртуальной таблицей ОстаткиИОбороты и методом ДвиженияИГраницыПериода, платформа старается максимально корректно обработать входящие даты, но явная передача объекта Граница через код (как в Решении 1) остается самым надежным методом.

Подведем итоги

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

  1. Старайтесь обучать пользователей использовать начало дня (00:00:00) для отчетов, так как это наиболее прозрачная точка отсчета.
  2. Используйте выражения СКД для автоматического приведения дат к началу следующего дня или конца текущего.
  3. Применяйте объект Граница в коде, если отчет строится программно или требует исключительной точности.
  4. Проверяйте роли полей в наборе данных СКД. Убедитесь, что для полей остатков правильно указаны роли Начальный остаток и Конечный остаток, а также соответствующие им поля периодов.

Соблюдение этих правил позволит вам избежать «дурацких вопросов» от пользователей и гарантирует высокую достоверность управленческой отчетности.

← На главную