Как составить запрос для поиска просрочки более 3 дней в периоде

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Торговля и дистрибуция
← На главную

В практике разработки на платформе 1С часто возникает задача анализа дебиторской задолженности. Одной из самых востребованных проверок является выявление случаев, когда контрагент допустил просрочку платежа на определенное количество дней (например, более трех) хотя бы один раз за выбранный интервал времени. В современных конфигурациях, таких как 1С:ERP, Комплексная автоматизация 2 или Управление торговлей 11, для этих целей используется регистр накопления РасчетыСКлиентамиПоСрокам.

В данной статье мы разберем, как правильно построить запрос к виртуальным таблицам, какие ошибки часто допускают разработчики при сравнении дат и как оптимизировать выборку данных.

Анализ исходных данных и выбор виртуальной таблицы

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

Важный нюанс: использование периодичности День заставляет систему генерировать временные срезы на каждую дату, когда были движения, а при использовании параметра ДвиженияИГраницыПериода — и на начало/конец периода. Рассмотрим структуру запроса, который ляжет в основу нашего решения.


ВЫБРАТЬ
    Расчеты.Период КАК ДатаПроверки,
    Расчеты.АналитикаУчетаПоПартнерам.Контрагент КАК Контрагент,
    Расчеты.ДолгКонечныйОстаток КАК СуммаДолга,
    Расчеты.ДатаПлановогоПогашения КАК ДатаПлановогоПогашения
ИЗ
    РегистрНакопления.РасчетыСКлиентамиПоСрокам.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, День, ДвиженияИГраницыПериода, ) КАК Расчеты
ГДЕ
    Расчеты.ДолгКонечныйОстаток > 0

Разбор логической ошибки при сравнении дат

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

Рассмотрим условие: ДОБАВИТЬКДАТЕ(ДатаПлановогоПогашения, ДЕНЬ, 3) > Период. Почему оно работает неверно? Давайте подставим цифры:

  1. Пусть ДатаПлановогоПогашения = 01.08.2023.
  2. Добавляем 3 дня: получаем 04.08.2023.
  3. Проверяем на дату 02.08.2023 (это наш Период).
  4. 04.08.2023 > 02.08.2023? Да. Условие выполнилось, хотя просрочка всего 1 день!

Чтобы найти просрочку более 3 дней, дата проверки (Период) должна быть строго больше, чем дата планового погашения плюс три дня. Выясним причину: просрочка наступает тогда, когда текущий день «обогнал» крайний срок оплаты.

Правильное условие:


ГДЕ
    Расчеты.Период > ДОБАВИТЬКДАТЕ(Расчеты.ДатаПлановогоПогашения, ДЕНЬ, 3)
    И Расчеты.ДолгКонечныйОстаток > 500

Реализация условия «хотя бы один раз в периоде»

Поскольку нам нужно получить список контрагентов, которые нарушили условия договора хотя бы единожды, нам не нужны все строки по дням в итоговом результате. Мы воспользуемся механизмом группировки или оператором РАЗЛИЧНЫЕ. Рассмотрим пошаговый алгоритм построения эффективного запроса.

Шаг 1. Выбираем все факты просрочки во временную таблицу. Назовем ее ВТ_ВсеПросрочки.


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

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

Оптимизация и работа с временем в датах

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

Для корректного сравнения «день в день» рекомендуется приводить все значения к началу дня. Это исключит ситуации, когда разница в несколько часов влияет на результат функции РАЗНОСТЬДАТ.

Рассмотрим итоговый вариант запроса, который можно использовать в отчете или обработке:


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

Альтернативный подход: когда данных слишком много

Если база данных имеет огромный объем и запрос по дням (периодичность День) выполняется слишком долго, можно применить другой подход. Вместо перебора всех дней мы можем проанализировать только два состояния:

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

Этот метод значительно сложнее в реализации (требуется объединение таблиц остатков и оборотов), но он работает в разы быстрее, так как системе не нужно генерировать виртуальные записи на каждый пустой день между движениями.

Подведем итог: для получения корректного результата важно следить за направлением знака сравнения в условиях дат и обязательно учитывать, что просрочка — это разница между текущим моментом наблюдения и плановым сроком. Использование виртуальной таблицы ОстаткиИОбороты с группировкой по контрагенту позволяет решить задачу «хотя бы одной просрочки» стандартными средствами языка запросов 1С без использования медленного перебора в коде (циклом Для каждого).

← На главную