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