Как в 1С отобрать контрагентов по дате последней реализации и отсутствию задолженности

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

При работе в конфигурации «Управление торговлей 10.3» или аналогичных решениях на обычных формах часто возникает задача анализа «спящей» клиентской базы. Типичный сценарий: необходимо найти клиентов, которые когда-то совершали покупки (например, более полугода назад), но на текущий момент ничего не должны компании. Это позволяет выделить сегмент лояльных, но переставших покупать контрагентов для маркетинговых активностей.

В данной статье мы подробно разберем, как построить запрос, который корректно определит дату последней отгрузки, правильно проверит остатки по регистрам взаиморасчетов и эффективно устранит дублирование строк, возникающее при совпадении времени документов.

Анализируем проблему получения «последнего» документа

Первая сложность, с которой сталкиваются разработчики, — это получение одного единственного документа реализации для каждого контрагента. Если использовать простое условие МАКСИМУМ(Дата), система может вернуть несколько документов, если они были созданы в одну и ту же секунду (например, при групповом перепроведении или импорте данных). Рассмотрим, почему стандартный подход с соединением по дате может выдавать дубли.

Проанализируем ситуацию: если у контрагента «Василек» есть две реализации от 01.01.2023 12:00:00, то внутреннее соединение по дате выберет обе записи. Чтобы этого избежать, нам необходимо группировать данные не только по времени, но и по ссылке на документ, так как ссылка в системе 1С всегда уникальна.

Шаг 1: Получение уникальных последних документов

Разберем по шагам, как составить вложенный запрос, который гарантированно вернет одну ссылку на реализацию для каждого контрагента. Мы будем использовать связку максимальной даты и максимальной ссылки.


ВЫБРАТЬ
    Реализация.Контрагент КАК Контрагент,
    МАКСИМУМ(Реализация.Дата) КАК ДатаПоследнегоДокумента,
    МАКСИМУМ(Реализация.Ссылка) КАК СсылкаНаДокумент
ПОМЕСТИТЬ ВТ_ПоследниеДокументы
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Проведен = ИСТИНА
СГРУППИРОВАТЬ ПО
    Реализация.Контрагент
ХАВИНГ
    МАКСИМУМ(Реализация.Дата) < &ДатаСреза
;

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

Шаг 2: Проверка задолженности по регистру накопления

Выясним причину, по которой нельзя проверять долг через документы реализации. Задолженность контрагента — это ресурс регистра, а не реквизит документа. В 1С:УТ 10.3 для этого предназначен регистр накопления ВзаиморасчетыСКонтрагентами.

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

Посмотрим на пример правильного соединения с виртуальной таблицей остатков:


ВЫБРАТЬ
    Доки.Контрагент КАК Контрагент,
    Доки.Контрагент.ИНН КАК ИНН,
    Доки.ДатаПоследнегоДокумента КАК ДатаПоследнегоДокумента,
    Доки.СсылкаНаДокумент КАК Ссылка
ИЗ
    ВТ_ПоследниеДокументы КАК Доки
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ВзаиморасчетыСКонтрагентами.Остатки(&Период, ) КАК Остатки
        ПО Доки.Контрагент = Остатки.Контрагент
ГДЕ
    ЕСТЬNULL(Остатки.СуммаВзаиморасчетовОстаток, 0) = 0

Разберем подробнее конструкцию ЛЕВОЕ СОЕДИНЕНИЕ. Мы берем всех наших найденных контрагентов и «приклеиваем» к ним остатки долга. Если у контрагента вообще нет записей в регистре (он всё оплатил и оборотов давно не было), система вернет NULL. Именно поэтому мы используем функцию ЕСТЬNULL(..., 0), чтобы превратить отсутствие данных в число 0 и корректно сравнить его в условии ГДЕ.

Шаг 3: Итоговый консолидированный запрос

Теперь объединим всё вышесказанное в единую структуру. Мы добавим получение основной информации о контрагенте (ИНН, основной менеджер) и обеспечим чистоту результата без дублей.


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

Рекомендации по оптимизации и точности данных

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

  1. Учет кредиторской задолженности: В условии ГДЕ мы указали <= 0. Это сделано для того, чтобы в отчет попали и те, кому мы ничего не должны, и те, перед кем у нас есть переплата (отрицательный остаток в регистре взаиморасчетов). Если вам нужны строго «нули», используйте = 0.
  2. Фильтрация по типу договора: В реальных базах у контрагента могут быть договоры «С поставщиком» и «С покупателем». Если мы анализируем продажи, стоит добавить во вложенный запрос условие по виду договора, чтобы не учитывать случайные возвраты или закупки.
  3. Использование индексации: Если в базе данных десятки тысяч контрагентов, работа с виртуальными таблицами остатков может замедляться. Рекомендуется всегда передавать в параметры виртуальной таблицы &ТекущаяДата, чтобы система не рассчитывала итоги на пустую дату (конец времен).
  4. Момент времени: Если вы хотите добиться абсолютной точности в определении «последнего» документа, вместо МАКСИМУМ(Дата) и МАКСИМУМ(Ссылка) в коде 1С часто используют МАКСИМУМ(МоментВремени), однако в языке запросов это поле доступно для выбора, но не всегда корректно работает в агрегатных функциях СУБД, поэтому связка Дата + Ссылка остается самым надежным вариантом.

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

← На главную