Как в запросе 1С проверить просрочку задач с учетом рабочих дней и выходных

Программист Управленческий учет IT и автоматизация бизнеса
← На главную

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

Постановка задачи и анализ ограничений

Рассмотрим ситуацию, когда нам необходимо получить список задач со следующими условиями:

  1. Выборка только тех задач, которые не выполнены на текущий момент (или выполнены с опозданием) в рамках указанного месяца.
  2. Срок выполнения превысил 3 рабочих дня с момента создания.
  3. Необходимо учитывать задачи, созданные в последних числах предыдущего месяца (29, 30, 31 число), если они попадают под условие просрочки в текущем периоде.

Проанализируем ситуацию, когда у разработчика нет прямого доступа к производственному календарю или требуется быстрое решение "здесь и сейчас" с помощью консоли запросов.

Решение через эмуляцию выходных дней в запросе

Если мы не можем использовать регистр сведений ДанныеПроизводственногоКалендаря, нам придется использовать математическую логику на основе функции ДЕНЬНЕДЕЛИ. Суть метода заключается в том, что если задача была создана ближе к концу недели, то к стандартным 3 дням просрочки добавляются 2 выходных дня (суббота и воскресенье).

Рассмотрим логику смещения:

Пример реализации такой логики в тексте запроса:


ВЫБРАТЬ
    Напоминания.Ссылка КАК Ссылка,
    Напоминания.Дата КАК ДатаСоздания,
    Напоминания.ДатаВыполнения КАК ДатаВыполнения,
    Напоминания.Выполнено КАК СтатусВыполнено
ИЗ
    Справочник.Напоминания КАК Напоминания
ГДЕ
    (ВЫБОР
        КОГДА ДЕНЬНЕДЕЛИ(Напоминания.Дата) = 4 ИЛИ ДЕНЬНЕДЕЛИ(Напоминания.Дата) = 5
            ТОГДА РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 5
        КОГДА ДЕНЬНЕДЕЛИ(Напоминания.Дата) = 6
            ТОГДА РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 4
        ИНАЧЕ РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 3
    КОНЕЦ)
    И Напоминания.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Сегодня, МЕСЯЦ) И КОНЕЦПЕРИОДА(&Сегодня, МЕСЯЦ)

Обработка задач прошлого месяца и невыполненных задач

Проанализируем важный нюанс: если задача еще не выполнена (Выполнено = ЛОЖЬ), поле ДатаВыполнения может быть не заполнено. В этом случае нам нужно сравнивать дату создания не с датой выполнения, а с текущей датой.

Чтобы захватить "хвосты" прошлого месяца, мы можем объединить результаты двух запросов. Первый выберет просроченные и уже закрытые задачи, а второй — те, которые до сих пор висят в работе, включая созданные за 5 дней до начала текущего месяца.

Применим метод объединения (ОБЪЕДИНИТЬ ВСЕ):


// Часть 1: Выполненные задачи с опозданием за текущий месяц
ВЫБРАТЬ
    Напоминания.Исполнитель,
    Напоминания.Владелец КАК Задача,
    Напоминания.ДатаВыполнения
ИЗ
    Справочник.Напоминания КАК Напоминания
ГДЕ
    Напоминания.Выполнено = ИСТИНА
    И Напоминания.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Сегодня, МЕСЯЦ) И КОНЕЦПЕРИОДА(&Сегодня, МЕСЯЦ)
    И (ВЫБОР
        КОГДА ДЕНЬНЕДЕЛИ(Напоминания.Дата) МЕЖДУ 4 И 6 
            ТОГДА РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 5
        ИНАЧЕ РАЗНОСТЬДАТ(Напоминания.Дата, Напоминания.ДатаВыполнения, ДЕНЬ) > 3
    КОНЕЦ)

ОБЪЕДИНИТЬ ВСЕ

// Часть 2: Невыполненные задачи, включая конец прошлого месяца
ВЫБРАТЬ
    Напоминания.Исполнитель,
    Напоминания.Владелец,
    &Сегодня
ИЗ
    Справочник.Напоминания КАК Напоминания
ГДЕ
    Напоминания.Выполнено = ЛОЖЬ
    И Напоминания.Дата МЕЖДУ ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&Сегодня, МЕСЯЦ), ДЕНЬ, -5) И КОНЕЦПЕРИОДА(&Сегодня, МЕСЯЦ)
    И (ВЫБОР
        КОГДА ДЕНЬНЕДЕЛИ(Напоминания.Дата) МЕЖДУ 4 И 6 
            ТОГДА РАЗНОСТЬДАТ(Напоминания.Дата, &Сегодня, ДЕНЬ) > 5
        ИНАЧЕ РАЗНОСТЬДАТ(Напоминания.Дата, &Сегодня, ДЕНЬ) > 3
    КОНЕЦ)

Профессиональный подход: использование производственного календаря

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

Разберем по шагам, как это сделать в запросе:

  1. Создадим временную таблицу со списком рабочих дней из производственного календаря за нужный период.
  2. Для каждой задачи посчитаем количество записей в этой таблице, которые попадают в интервал между датой создания и датой выполнения.
  3. Если количество записей (рабочих дней) больше 3 — задача просрочена.

Пример фрагмента запроса с использованием календаря:


ВЫБРАТЬ
    Напоминания.Владелец КАК Задача,
    КОЛИЧЕСТВО(Календарь.Дата) КАК КолРабочихДней
ИЗ
    Справочник.Напоминания КАК Напоминания
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
        ПО Календарь.Дата > Напоминания.Дата
        И Календарь.Дата <= Напоминания.ДатаВыполнения
ГДЕ
    Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
СГРУППИРОВАТЬ ПО
    Напоминания.Владелец
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(Календарь.Дата) > 3

Рекомендации по оптимизации

При работе с консолью запросов и большими объемами данных важно помнить о производительности. Использование РАЗЛИЧНЫЕ или сложных условий ВЫБОР в секции ГДЕ может замедлить выполнение.

Проанализируем ключевые советы:

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

← На главную