Почему в запрос остатков не попадают движения закрытия месяца и как это исправить?

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

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

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

Выясняем причину: особенности работы со временем в 1С

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

Обычные документы регистрируются в базе в течение всего дня в разные секунды (например, в 12:15:30 или 18:40:00). Поскольку эти секунды предшествуют времени 23:59:59, движения таких документов без проблем попадают в отчет.

Однако регламентные документы и операции закрытия месяца создаются системой автоматически и записываются строго на самую последнюю секунду периода — 23:59:59. Поскольку запрос рассчитывает остатки на начало этой секунды, движения регламентной операции остаются за бортом расчета.

Давайте разберем по шагам, как решить эту проблему несколькими способами.

Способ 1. Использование объекта Граница (Рекомендуемый)

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

Среди разработчиков существует популярное заблуждение (которое встречается и в сообщениях форума), что в конструктор объекта Граница в качестве первого параметра можно передавать только документ или МоментВремени. Это не так. Объект Граница отлично принимает обычную дату.

Рассмотрим пример кода, который решает проблему:


// Получаем конец дня для выбранной даты окончания
КонечнаяДата = КонецДня(ДатаОкончания);

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

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

Запрос.УстановитьПараметр("КонПериода", ПараметрГраница);
Запрос.УстановитьПараметр("ВыбСчет", СчетСв);

РезультатЗапроса = Запрос.Выполнить();

Использование конструкции Новый Граница(КонецДня(Дата), ВидГраницы.Включая) гарантирует, что система рассчитает остатки на конец последней секунды дня, включая все движения, совершенные в 23:59:59.

Способ 2. Смещение периода запроса на начало следующего дня

Если по какой-то причине вы не хотите создавать объект Граница в коде (например, при быстрой отладке или динамическом построении текста запроса), можно прибегнуть к математическому смещению времени на одну секунду вперед.

Посмотрим на пример реализации:


// Прибавляем к концу дня 1 секунду, чтобы получить 00:00:00 следующего дня
ДатаСмещения = КонецДня(ДатаОкончания) + 1;

Запрос.УстановитьПараметр("КонПериода", ДатаСмещения);

В данном случае запрос рассчитает остатки на начало секунды 00:00:00 следующего дня (например, 1 января нового года). Все документы предыдущего дня, включая регламентные операции на 23:59:59, будут учтены.

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

Способ 3. Решение проблемы в Системе компоновки данных (СКД)

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

Проанализируем два основных варианта настройки СКД:

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

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

    Это автоматически сдвинет время расчета остатков на начало следующего дня без написания кода на встроенном языке.
  2. Разделение параметров на пользовательские и служебные. Вы можете создать доступный пользователю параметр ПериодОтчета (тип СтандартныйПериод) и скрытый параметр ПериодГраница, в выражении которого программно рассчитывать объект Граница при компоновке макета отчета.

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

← На главную