При разработке отчетов в Системе компоновки данных (СКД) одной из частых задач является ограничение выборки динамическим интервалом времени. Например, требуется вывести продажи, остатки или объемы работ за последние три месяца относительно текущей даты. На первый взгляд задача кажется простой, однако начинающие разработчики часто сталкиваются со специфическими ошибками: функции расчета дат не работают в параметрах, компоновщик выдает сообщения о синтаксических ошибках, либо отчет возвращает некорректный интервал времени.
В этой статье мы подробно разберем, почему возникают эти сложности, проанализируем разницу в синтаксисе различных механизмов платформы 1С и рассмотрим три надежных способа решения этой задачи.
Основная причина трудностей при решении подобных задач — смешивание разных стандартов написания кода в экосистеме 1С. Разработчику необходимо четко разделять три контекста:
КонецМесяца(), ДобавитьМесяц() или ТекущаяДата().КОНЕЦПЕРИОДА() и ДОБАВИТЬКДАТЕ(), причем тип периода пишется как ключевое слово без кавычек (например, МЕСЯЦ, ДЕНЬ).КонецПериода() требует передачи типа периода в виде строки в кавычках (например, "Месяц"). Использование функции встроенного языка КонецМесяца() или синтаксиса запросов без кавычек здесь приведет к ошибке компоновки.Кроме того, при использовании автозаполнения СКД автоматически создает скрытые системные параметры НачалоПериода и КонецПериода для виртуальных таблиц оборотов. Прямая попытка переопределить их формулами внутри текста запроса без учета механизмов СКД часто приводит к конфликтам компоновщика.
Рассмотрим по шагам три способа реализации нашей задачи.
Самый правильный и изящный способ с точки зрения архитектуры СКД — оставить текст запроса максимально простым, а всю логику расчета дат перенести на вкладку «Параметры» компоновщика данных. Это позволит избежать нагромождения формул в самом запросе.
Допустим, в запросе СКД используется обращение к виртуальной таблице оборотов:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура,
ПродажиОбороты.КоличествоОборот
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты
Для того чтобы настроить автоматический расчет параметров за 3 последних месяца, выполним следующие действия:
НачалоПериода и КонецПериода.Вариант А: Три месяца, включая текущий. Например, сегодня 15 февраля. Нам нужны полные декабрь, январь и текущий февраль. Началом периода должно стать 1 декабря. Смещение назад составляет ровно 2 месяца.
В колонку «Выражение» для параметра НачалоПериода запишем формулу на языке СКД:
НачалоПериода(ДобавитьКДате(ТекущаяДата(), "Месяц", -2), "Месяц")
Для параметра КонецПериода запишем формулу, которая вернет конец текущего месяца:
КонецПериода(ТекущаяДата(), "Месяц")
Вариант Б: Три последних полностью завершенных месяца (без текущего). Например, сегодня 15 февраля. Нам нужны полные ноябрь, декабрь и январь. Начало периода — 1 ноября (смещение на 3 месяца назад), конец периода — 31 января (смещение на 1 месяц назад).
Выражение для НачалоПериода:
НачалоПериода(ДобавитьКДате(ТекущаяДата(), "Месяц", -3), "Месяц")
Выражение для КонецПериода:
КонецПериода(ДобавитьКДате(ТекущаяДата(), "Месяц", -1), "Месяц")
При таком подходе СКД при каждом запуске отчета будет автоматически и безошибочно вычислять нужные даты, используя системное время.
Если по каким-то причинам требуется жестко прописать формулу расчета прямо в тексте запроса, мы можем использовать функции языка запросов. В этом случае параметром отчета будет выступать некая базовая дата (например, &ДатаДок или &ВыбДата), от которой будет строиться смещение.
Посмотрим, как выглядит текст запроса для получения данных за 3 последних месяца (включая текущий):
ВЫБРАТЬ
ПродажиОбороты.Номенклатура,
ПродажиОбороты.КоличествоОборот КАК Количество
ИЗ
РегистрНакопления.Продажи.Обороты(
НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаДок, МЕСЯЦ, -2), МЕСЯЦ),
КОНЕЦПЕРИОДА(&ДатаДок, МЕСЯЦ),
Запись,
) КАК ПродажиОбороты
Важные нюансы этого способа:
МЕСЯЦ пишутся без кавычек.Запись. Это гарантирует корректную работу границ периодов при получении оборотов.{}, которые управляют необязательными элементами компоновщика. Однако при явном заполнении параметров виртуальной таблицы формулами, как в примере выше, автозаполнение обычно отрабатывает корректно.Этот способ является стандартом разработки в среде 1С. Он позволяет задать отчету динамический период по умолчанию (за последние 3 месяца), но при этом оставляет пользователю удобную возможность интерактивно изменить этот период при необходимости.
Разберем этот вариант по шагам:
ПериодОтчета. Установим для него тип данных СтандартныйПериод.НачалоПериода и КонецПериода установим флаг «Ограничение доступности».НачалоПериода пропишем связь со стандартным периодом:
&ПериодОтчета.ДатаНачала
КонецПериода пропишем:
&ПериодОтчета.ДатаОкончания
Теперь пользователь в настройках отчета будет видеть удобное поле выбора периода, где он сможет одним нажатием выбрать «Текущий месяц», «Прошлый квартал» или установить произвольный интервал, а виртуальная таблица запроса всегда будет получать точные даты начала и окончания.
При работе с датой окончания периода на уровне платформы 1С часто возникает проблема «последней секунды». Если конечная дата установлена без указания времени (например, 31.01.2024 00:00:00), то документы, проведенные в течение этого последнего дня, могут не попасть в выборку виртуальной таблицы оборотов.
Именно поэтому использование функции КОНЕЦПЕРИОДА() в запросе или КонецПериода() в выражениях СКД является критически важным. Данные функции приводят дату к концу указанного интервала с точностью до секунды (например, 31.01.2024 23:59:59), что гарантирует полное и корректное попадание всех движений регистра за последний день выбранного периода.