Как в запросах и отчетах 1С изменить начало недели (например, с четверга по среду)

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

В процессе разработки отчетов в среде 1С:Предприятие программисты регулярно сталкиваются с необходимостью группировки данных по периодам. Платформа предоставляет отличные встроенные инструменты для работы со стандартным календарем, где неделя по умолчанию начинается в понедельник. Однако реальный бизнес живет по своим правилам. Финансовые недели, графики сменности, периоды поставок или маркетинговые акции часто требуют нестандартных рамок — например, когда неделя должна строго начинаться с четверга и заканчиваться в среду следующей недели.

В этой статье мы подробно разберем, как решить эту задачу на уровне запросов СУБД, механизмов Системы компоновки данных (СКД) и интерфейса пользователя. Мы проанализируем различные подходы — от изящных математических формул до надежных архитектурных решений с использованием вспомогательных таблиц.

Метод 1. Изящная математическая формула смещения дат в запросе

Давайте разберем по шагам, как получить дату начала такой нестандартной недели прямо внутри запроса без использования тяжелых условий. Для этого мы применим комбинацию функций ДОБАВИТЬКДАТЕ и НАЧАЛОПЕРИОДА.

Идея заключается в том, чтобы временно «сдвинуть» анализируемую дату вперед на такое количество дней, чтобы четверг стал визуальным аналогом понедельника для стандартной функции НАЧАЛОПЕРИОДА, а затем вернуть результат обратно. Для недели, начинающейся с четверга, это смещение составляет ровно 4 дня.

Посмотрим на пример формулы, которую мы можем написать в тексте запроса:


ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(Продажи.Период, ДЕНЬ, 4), НЕДЕЛЯ), ДЕНЬ, -4) КАК НачалоНестандартнойНедели

Проанализируем ситуацию и детально разберем, как работает эта математическая модель на конкретных примерах дат:

  1. Пример 1: Анализируем пятницу (27.10.2023). Наша цель — получить четверг (26.10.2023).
    1. Прибавляем 4 дня к исходной дате: 27.10.2023 + 4 дня = 31.10.2023 (это вторник следующей календарной недели).
    2. Применяем функцию НАЧАЛОПЕРИОДА(..., НЕДЕЛЯ): началом недели для вторника 31.10.2023 будет понедельник 30.10.2023.
    3. Вычитаем 4 дня из полученного понедельника: 30.10.2023 - 4 дня = 26.10.2023 (четверг). Формула отработала абсолютно верно!
  2. Пример 2: Анализируем среду (01.11.2023). Среда — это последний день нашей нестандартной недели, поэтому результатом по-прежнему должен быть четверг (26.10.2023).
    1. Прибавляем 4 дня: 01.11.2023 + 4 дня = 05.11.2023 (это воскресенье).
    2. Находим начало недели для воскресенья 05.11.2023: это понедельник 30.10.2023.
    3. Вычитаем 4 дня: 30.10.2023 - 4 дня = 26.10.2023 (четверг). Снова точный результат!
  3. Пример 3: Анализируем новый четверг (02.11.2023). Это первый день следующей недели, результатом должен стать именно этот день — 02.11.2023.
    1. Прибавляем 4 дня: 02.11.2023 + 4 дня = 06.11.2023 (это понедельник новой календарной недели).
    2. Начало недели для понедельника 06.11.2023 — это сам понедельник 06.11.2023.
    3. Вычитаем 4 дня: 06.11.2023 - 4 дня = 02.11.2023 (четверг). Логика работает безупречно на любых стыках дат.

Метод 2. Использование условной конструкции ВЫБОР КОГДА

Если математический метод кажется вам слишком абстрактным или его тяжело читать коллегам по разработке, мы можем воспользоваться более наглядной условной конструкцией в запросе. Для этого задействуем функцию ДЕНЬНЕДЕЛИ.

Логика нашего условия проста: если порядковый номер дня недели больше или равен 4 (то есть это четверг, пятница, суббота или воскресенье), то началом нашей производственной недели будет четверг текущей календарной недели. Если же день недели меньше 4 (понедельник, вторник, среда), то началом будет четверг предыдущей календарной недели.

Рассмотрим подробнее реализацию этого алгоритма в запросе:


ВЫБОР 
    КОГДА ДЕНЬНЕДЕЛИ(Продажи.Период) >= 4 
        ТОГДА ДОБАВИТЬКДАТЕ(Продажи.Период, ДЕНЬ, 4 - ДЕНЬНЕДЕЛИ(Продажи.Период)) 
    ИНАЧЕ ДОБАВИТЬКДАТЕ(Продажи.Период, ДЕНЬ, -(ДЕНЬНЕДЕЛИ(Продажи.Период) + 3)) 
КОНЕЦ КАК НачалоНестандартнойНедели

Этот способ более многословен, но он наглядно показывает логику расчетов. Например, если функция ДЕНЬНЕДЕЛИ возвращает нам 2 (вторник), запрос пойдет по ветке ИНАЧЕ и вычтет из вторника 5 дней -(2 + 3) = -5, мгновенно перемещая нас на четверг прошлой недели.

Метод 3. Реализация на уровне Вычисляемых полей СКД

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

Давайте настроим этот механизм по шагам:

  1. Откроем схему компоновки данных нашего отчета и перейдем на вкладку Вычисляемые поля.
  2. Добавим новую строку. Зададим имя поля, например, ПроизводственнаяНеделя.
  3. В колонку Выражение вставим нашу формулу смещения. Обратите внимание на синтаксическое отличие выражений СКД от стандартных запросов: типы периодов (например, день или неделя) в функциях СКД обязательно должны передаваться в виде строковых литералов в кавычках.

Выражение для вычисляемого поля СКД будет выглядеть следующим образом:


ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(Период, "ДЕНЬ", 4), "НЕДЕЛЯ"), "ДЕНЬ", -4)

После добавления этого поля мы можем использовать его на вкладке Настройки в качестве поля группировки. СКД автоматически сгруппирует все наши детальные записи по рассчитанным четвергам.

Метод 4. Архитектурный подход со вспомогательной таблицей периодов

Рассмотренные выше методы вычисления дат «на лету» отлично подходят для простых отчетов. Однако у них есть один фундаментальный недостаток — проблема дополнения периодов. Если в течение какой-то из наших нестандартных недель у компании не было продаж или движений по регистру, эта неделя просто выпадет из результирующей таблицы отчета. Стандартная системная функция дополнения периодов СКД не сможет восстановить пропущенные нестандартные недели, поскольку она ничего не знает о нашей логике сдвига.

Чтобы решить эту проблему профессионально, применим классический архитектурный подход с использованием вспомогательного календаря. Разберем этот алгоритм:

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

ЛЕВОЕ СОЕДИНЕНИЕ ВрТаблицаПериодов КАК Периоды
ПО Продажи.Период МЕЖДУ Периоды.ДатаНачала И Периоды.ДатаОкончания

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

Метод 5. Программное заполнение выбора периода для пользователя

С точки зрения юзабилити, стандартный диалог выбора периода 1С становится неудобным для пользователя, работающего по нестандартному календарю. Кнопки вроде «Текущая неделя» или «Предыдущая неделя» будут устанавливать границы с понедельника по воскресенье, что приведет к искажению данных в отчете.

Для создания комфортной рабочей среды пользователя мы можем применить следующий подход:

  1. Скроем со стандартной формы отчета типовую кнопку выбора периода.
  2. Разместим на форме собственное поле ввода со списком значений (выпадающий список).
  3. При открытии формы или программно заполним этот список понятными текстовыми представлениями, например: «Текущая произв. неделя», «Предыдущая произв. неделя», «Последние 4 недели».
  4. При выборе пользователем любого из этих пунктов, напишем обработчик на встроенном языке 1С, который точно рассчитает даты «с четверга по среду» и запишет их в скрытые параметры схемы компоновки данных.

Рассмотрим пример кода на встроенном языке для расчета текущей производственной недели:


ТекущаяДата = ТекущаяДатаСеанса();
// Вычисляем начало текущей нестандартной недели
НачалоЭтойНедели = ДобавитьКДате(НачалоПериода(ДобавитьКДате(ТекущаяДата, "ДЕНЬ", 4), "НЕДЕЛЯ"), "ДЕНЬ", -4);
КонецЭтойНедели = КонецДня(ДобавитьКДате(НачалоЭтойНедели, "ДЕНЬ", 6));

Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("НачалоПериода", НачалоЭтойНедели);
Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("КонецПериода", КонецЭтойНедели);

Этот код гарантирует, что отчет пользователя всегда будет формироваться строго в границах бизнес-логики компании.

Резюме

Мы рассмотрели несколько эффективных способов реализации нестандартных еженедельных периодов в системе 1С:Предприятие. Математический метод смещения дат через ДОБАВИТЬКДАТЕ идеален для быстрого решения задач «на лету» в консоли запросов. Метод с использованием ВЫБОР КОГДА обеспечивает отличную читаемость кода. Применение вычисляемых полей СКД позволяет гибко управлять группировками в интерфейсе отчетов, а связывание со вспомогательной таблицей периодов является самым надежным архитектурным решением, гарантирующим вывод пустых периодов без потери данных.

← На главную