При разработке отчетов и проведении проверок в платформе «1С:Предприятие» программисты часто сталкиваются со следующей проблемой: при получении остатков на конец месяца (например, на 31.12.2019) в результаты запроса не попадают данные регламентных операций. Это могут быть операции закрытия месяца, амортизация, корректировки стоимости или погашение стоимости спецодежды и спецоснастки. В то же время обычные документы (поступления, реализации), проведенные в этот же день, учитываются корректно.
В этой статье мы подробно разберем, почему возникает такая ситуация, развеем популярные заблуждения среди разработчиков и рассмотрим несколько надежных способов решения этой проблемы.
Для начала проанализируем, как платформа «1С:Предприятие» работает с типом данных Дата и виртуальными таблицами остатков. Тип данных Дата хранит значение с точностью до секунды. Когда мы передаем в параметры виртуальной таблицы (например, РегистрБухгалтерии.Хозрасчетный.Остатки) значение даты окончания периода, платформа рассчитывает итоги на начало этой секунды. То есть, передавая дату 31.12.2019 23:59:59, мы фактически просим систему показать остатки, исключая саму эту секунду.
Обычные документы регистрируются в базе в течение всего дня в разные секунды (например, в 12:15:30 или 18:40:00). Поскольку эти секунды предшествуют времени 23:59:59, движения таких документов без проблем попадают в отчет.
Однако регламентные документы и операции закрытия месяца создаются системой автоматически и записываются строго на самую последнюю секунду периода — 23:59:59. Поскольку запрос рассчитывает остатки на начало этой секунды, движения регламентной операции остаются за бортом расчета.
Давайте разберем по шагам, как решить эту проблему несколькими способами.
Самым методически верным и безопасным способом решения проблемы в среде 1С является использование специального объекта Граница. Этот объект позволяет явно указать платформе, нужно ли включать документы, записанные на граничную секунду, в расчет остатков.
Среди разработчиков существует популярное заблуждение (которое встречается и в сообщениях форума), что в конструктор объекта Граница в качестве первого параметра можно передавать только документ или МоментВремени. Это не так. Объект Граница отлично принимает обычную дату.
Рассмотрим пример кода, который решает проблему:
// Получаем конец дня для выбранной даты окончания
КонечнаяДата = КонецДня(ДатаОкончания);
// Создаем объект Граница с видом границы "Включая"
ПараметрГраница = Новый Граница(КонечнаяДата, ВидГраницы.Включая);
// Передаем границу в параметры запроса
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстатки.Счет КАК Счет,
| ХозрасчетныйОстатки.Субконто1 КАК Субконто1,
| ХозрасчетныйОстатки.СуммаОстаток КАК СуммаОстаток
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&КонПериода, Счет В ИЕРАРХИИ(&ВыбСчет), , ) КАК ХозрасчетныйОстатки";
Запрос.УстановитьПараметр("КонПериода", ПараметрГраница);
Запрос.УстановитьПараметр("ВыбСчет", СчетСв);
РезультатЗапроса = Запрос.Выполнить();
Использование конструкции Новый Граница(КонецДня(Дата), ВидГраницы.Включая) гарантирует, что система рассчитает остатки на конец последней секунды дня, включая все движения, совершенные в 23:59:59.
Если по какой-то причине вы не хотите создавать объект Граница в коде (например, при быстрой отладке или динамическом построении текста запроса), можно прибегнуть к математическому смещению времени на одну секунду вперед.
Посмотрим на пример реализации:
// Прибавляем к концу дня 1 секунду, чтобы получить 00:00:00 следующего дня
ДатаСмещения = КонецДня(ДатаОкончания) + 1;
Запрос.УстановитьПараметр("КонПериода", ДатаСмещения);
В данном случае запрос рассчитает остатки на начало секунды 00:00:00 следующего дня (например, 1 января нового года). Все документы предыдущего дня, включая регламентные операции на 23:59:59, будут учтены.
Важное предупреждение: хотя этот способ прост в реализации, у него есть скрытые риски. Если в вашей информационной базе в силу специфики бизнес-процессов, работы ночных смен или интеграций с внешними системами появятся документы, проведенные ровно в 00:00:00 следующего дня, их движения могут исказить остатки за предыдущий период. Кроме того, этот код менее очевиден для других разработчиков, которые будут поддерживать вашу конфигурацию в будущем.
Если вы разрабатываете отчет на СКД, передача объекта Граница напрямую из кода может вызвать неудобства, так как пользователи не смогут интерактивно выбирать этот тип данных на форме настроек отчета. В СКД эту проблему принято решать на уровне описания параметров.
Проанализируем два основных варианта настройки СКД:
КонецПериода с типом Дата), а в настройках схемы компоновки данных на вкладке «Параметры» для параметра виртуальной таблицы прописать следующее выражение:
ДобавитьКДате(КонецПериода(&КонецПериода, "День"), "Секунда", 1)
ПериодОтчета (тип СтандартныйПериод) и скрытый параметр ПериодГраница, в выражении которого программно рассчитывать объект Граница при компоновке макета отчета.
Выбор конкретного метода зависит от архитектуры вашего решения, но использование объекта Граница с видом Включая всегда остается приоритетным и наиболее надежным стандартом разработки в экосистеме «1С:Предприятие».