В процессе разработки систем контроля исполнительской дисциплины часто возникает задача: отобрать задачи, которые не были выполнены в течение определенного количества рабочих дней. Сложность заключается в том, что стандартная функция РАЗНОСТЬДАТ в языке запросов 1С учитывает календарные дни, игнорируя выходные и праздники. В этой статье мы разберем, как реализовать проверку срока выполнения (например, 3 рабочих дня) и как правильно обрабатывать задачи, созданные в конце прошлого месяца.
Рассмотрим ситуацию, когда нам необходимо получить список задач со следующими условиями:
Проанализируем ситуацию, когда у разработчика нет прямого доступа к производственному календарю или требуется быстрое решение "здесь и сейчас" с помощью консоли запросов.
Если мы не можем использовать регистр сведений ДанныеПроизводственногоКалендаря, нам придется использовать математическую логику на основе функции ДЕНЬНЕДЕЛИ. Суть метода заключается в том, что если задача была создана ближе к концу недели, то к стандартным 3 дням просрочки добавляются 2 выходных дня (суббота и воскресенье).
Рассмотрим логику смещения:
Пример реализации такой логики в тексте запроса:
ВЫБРАТЬ
Напоминания.Ссылка КАК Ссылка,
Напоминания.Дата КАК ДатаСоздания,
Напоминания.ДатаВыполнения КАК ДатаВыполнения,
Напоминания.Выполнено КАК СтатусВыполнено
ИЗ
Справочник.Напоминания КАК Напоминания
ГДЕ
(ВЫБОР
КОГДА ДЕНЬНЕДЕЛИ(Напоминания.Дата) = 4 ИЛИ ДЕНЬНЕДЕЛИ(Напоминания.Дата) = 5
ТОГДА РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 5
КОГДА ДЕНЬНЕДЕЛИ(Напоминания.Дата) = 6
ТОГДА РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 4
ИНАЧЕ РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 3
КОНЕЦ)
И Напоминания.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Сегодня, МЕСЯЦ) И КОНЕЦПЕРИОДА(&Сегодня, МЕСЯЦ)
Проанализируем важный нюанс: если задача еще не выполнена (Выполнено = ЛОЖЬ), поле ДатаВыполнения может быть не заполнено. В этом случае нам нужно сравнивать дату создания не с датой выполнения, а с текущей датой.
Чтобы захватить "хвосты" прошлого месяца, мы можем объединить результаты двух запросов. Первый выберет просроченные и уже закрытые задачи, а второй — те, которые до сих пор висят в работе, включая созданные за 5 дней до начала текущего месяца.
Применим метод объединения (ОБЪЕДИНИТЬ ВСЕ):
// Часть 1: Выполненные задачи с опозданием за текущий месяц
ВЫБРАТЬ
Напоминания.Исполнитель,
Напоминания.Владелец КАК Задача,
Напоминания.ДатаВыполнения
ИЗ
Справочник.Напоминания КАК Напоминания
ГДЕ
Напоминания.Выполнено = ИСТИНА
И Напоминания.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Сегодня, МЕСЯЦ) И КОНЕЦПЕРИОДА(&Сегодня, МЕСЯЦ)
И (ВЫБОР
КОГДА ДЕНЬНЕДЕЛИ(Напоминания.Дата) МЕЖДУ 4 И 6
ТОГДА РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 5
ИНАЧЕ РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 3
КОНЕЦ)
ОБЪЕДИНИТЬ ВСЕ
// Часть 2: Невыполненные задачи, включая конец прошлого месяца
ВЫБРАТЬ
Напоминания.Исполнитель,
Напоминания.Владелец,
&Сегодня
ИЗ
Справочник.Напоминания КАК Напоминания
ГДЕ
Напоминания.Выполнено = ЛОЖЬ
И Напоминания.Дата МЕЖДУ ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&Сегодня, МЕСЯЦ), ДЕНЬ, -5) И КОНЕЦПЕРИОДА(&Сегодня, МЕСЯЦ)
И (ВЫБОР
КОГДА ДЕНЬНЕДЕЛИ(Напоминания.Дата) МЕЖДУ 4 И 6
ТОГДА РАЗНОСТЬДАТ(Напоминания.Дата, &Сегодня, ДЕНЬ) > 5
ИНАЧЕ РАЗНОСТЬДАТ(Напоминания.Дата, &Сегодня, ДЕНЬ) > 3
КОНЕЦ)
Выясним причину, почему предыдущий метод считается несовершенным. Он не учитывает государственные праздники (например, новогодние каникулы или 8 марта), которые могут длиться неделю. Для точного расчета в конфигурациях, использующих БСП, следует обращаться к регистру ДанныеПроизводственногоКалендаря.
Разберем по шагам, как это сделать в запросе:
Пример фрагмента запроса с использованием календаря:
ВЫБРАТЬ
Напоминания.Владелец КАК Задача,
КОЛИЧЕСТВО(Календарь.Дата) КАК КолРабочихДней
ИЗ
Справочник.Напоминания КАК Напоминания
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
ПО Календарь.Дата > Напоминания.Дата
И Календарь.Дата <= Напоминания.ДатаВыполнения
ГДЕ
Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
СГРУППИРОВАТЬ ПО
Напоминания.Владелец
ИМЕЮЩИЕ
КОЛИЧЕСТВО(Календарь.Дата) > 3
При работе с консолью запросов и большими объемами данных важно помнить о производительности. Использование РАЗЛИЧНЫЕ или сложных условий ВЫБОР в секции ГДЕ может замедлить выполнение.
Проанализируем ключевые советы:
Дата).Напоминания.Выполнено = ЛОЖЬ.&ТекущаяДата, рассчитанный на стороне сервера как ТекущаяДатаСеанса(), чтобы избежать расхождений в часовых поясах.Таким образом, мы рассмотрели как упрощенный метод расчета просрочки через математическую модель выходных дней, так и более надежный способ с использованием производственного календаря. Для обучения и простых отчетов в консоли первый метод вполне применим, но для серьезных учетных систем рекомендуется интеграция с календарными графиками системы 1С.