В процессе работы с базой 1С часто возникает необходимость актуализировать список контрагентов. Одной из наиболее востребованных задач является выявление «спящих» или неактивных партнеров, с которыми не было никаких взаимодействий (отгрузок, оплат, поступлений) за определенный период времени. Это позволяет менеджерам сосредоточиться на активной клиентской базе, а администраторам — подготовить данные к архивации или удалению.
В этой статье мы подробно разберем, как реализовать подобную выборку с помощью механизмов запросов, проанализируем, какие регистры накопления следует задействовать, и исправим типичные ошибки, возникающие при выводе контактной информации таких контрагентов.
Прежде чем писать код, нам нужно определиться, что именно мы считаем «движением». В конфигурации «Управление торговлей 10.3» (и аналогичных на обычных формах) информация о взаимоотношениях с контрагентами хранится в нескольких ключевых регистрах. Рассмотрим их:
Как показывает практика, для самого широкого охвата лучше всего использовать виртуальные таблицы Обороты или ОстаткиИОбороты регистров расчетов. Проанализируем ситуацию: если у контрагента не было прихода и расхода по этим регистрам, значит, торговая деятельность не велась.
Общая логика запроса строится от обратного. Мы не ищем тех, у кого «пусто» в регистре (так как в регистре физически нет записей о тех, кто не работал), а выбираем всех контрагентов из справочника Контрагенты и исключаем из них тех, кто «засветился» в регистрах за выбранный период.
Рассмотрим по шагам создание такого запроса.
Для начала соберем всех, у кого движения были. Используем временную таблицу для оптимизации:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Взаиморасчеты.Контрагент КАК Контрагент
ПОМЕСТИТЬ ВрТаблицаАктивных
ИЗ
РегистрНакопления.ВзаиморасчетыСКонтрагентами.Обороты(&НачДата, &КонДата, , ) КАК Взаиморасчеты
;
Здесь мы используем виртуальную таблицу Обороты. Если за период с &НачДата по &КонДата были любые движения, контрагент попадет в эту выборку.
Теперь выберем всех контрагентов из справочника, которых НЕТ в нашей временной таблице. Рассмотрим пример кода:
ВЫБРАТЬ
Контрагенты.Ссылка КАК Ссылка,
Контрагенты.Наименование КАК Наименование
ИЗ
Справочник.Контрагенты КАК Контрагенты
ГДЕ
НЕ Контрагенты.Ссылка В (ВЫБРАТЬ Вр.Контрагент ИЗ ВрТаблицаАктивных КАК Вр)
И Контрагенты.ЭтоГруппа = ЛОЖЬ
И Контрагенты.ПометкаУдаления = ЛОЖЬ
Обратите внимание на важные фильтры: ЭтоГруппа = ЛОЖЬ (нам нужны только элементы, а не папки) и ПометкаУдаления = ЛОЖЬ (чтобы не анализировать тех, кто уже готовится к удалению).
Часто заказчику требуется не просто список имен, но и телефоны этих контрагентов, чтобы менеджеры могли совершить «холодный» обзвон. При добавлении таблицы КонтактнаяИнформация начинающие разработчики часто совершают ошибку, из-за которой контрагенты без указанных телефонов пропадают из отчета.
Выясним причину: если использовать ГДЕ для фильтрации типа контактной информации (например, «Телефон»), то при отсутствии телефона у контрагента вся строка отсекается, так как условие в ГДЕ не выполняется для значений NULL.
Проанализируем правильный вариант соединения таблиц:
ВЫБРАТЬ
Контрагенты.Ссылка КАК Контрагент,
ВЫРАЗИТЬ(КИ.Представление КАК СТРОКА(100)) КАК Телефон
ИЗ
Справочник.Контрагенты КАК Контрагенты
ЛЕВОЕ СОЕДИНЕНИЕ
РегистрСведений.КонтактнаяИнформация КАК КИ
ПО Контрагенты.Ссылка = КИ.Объект
И КИ.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон)
И КИ.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ТелефонКонтрагента)
ГДЕ
НЕ Контрагенты.Ссылка В (ВЫБРАТЬ Вр.Контрагент ИЗ ВрТаблицаАктивных)
И Контрагенты.ЭтоГруппа = ЛОЖЬ
Важный момент: условие по типу телефона перенесено в секцию ПО (ON). Это гарантирует, что ЛЕВОЕ СОЕДИНЕНИЕ сохранит всех контрагентов из левой таблицы (Справочник), даже если в правой таблице (Регистр сведений) для них не найдется подходящей записи. В этом случае в поле «Телефон» просто будет пустое значение.
Хотя конструкция ГДЕ НЕ Ссылка В (...) интуитивно понятна, с точки зрения производительности на больших базах данных (особенно при использовании SQL Server) эффективнее использовать ЛЕВОЕ СОЕДИНЕНИЕ с проверкой на NULL. Разберем этот пример:
ВЫБРАТЬ
Контрагенты.Ссылка КАК Ссылка
ИЗ
Справочник.Контрагенты КАК Контрагенты
ЛЕВОЕ СОЕДИНЕНИЕ
РегистрНакопления.ВзаиморасчетыСКонтрагентами.Обороты(&НачДата, &КонДата, , ) КАК Обороты
ПО Контрагенты.Ссылка = Обороты.Контрагент
ГДЕ
Обороты.Контрагент ЕСТЬ NULL
И Контрагенты.ЭтоГруппа = ЛОЖЬ
В данном случае система ищет совпадения в регистре. Если совпадений нет, поле Обороты.Контрагент примет значение NULL. Именно такие записи (те, по которым не было оборотов) и попадут в наш итоговый результат.
Рассмотрим ситуацию: движений за последние 2 года не было, но у контрагента висит неоплаченный долг десятилетней давности. Считать ли его «без движений»? С технической точки зрения — да, оборотов нет. С управленческой — нет, так как по нему есть сальдо.
Чтобы исключить таких контрагентов из списка «на удаление», рекомендуется использовать виртуальную таблицу ОстаткиИОбороты и проверять наличие конечного остатка:
ВЫБРАТЬ
Взаиморасчеты.Контрагент
ПОМЕСТИТЬ ВрИсключаемые
ИЗ
РегистрНакопления.ВзаиморасчетыСКонтрагентами.ОстаткиИОбороты(&НачДата, &КонДата, , , ) КАК Взаиморасчеты
ГДЕ
(Взаиморасчеты.СуммаВзаиморасчетовПриход <> 0
ИЛИ Взаиморасчеты.СуммаВзаиморасчетовРасход <> 0
ИЛИ Взаиморасчеты.СуммаВзаиморасчетовКонечныйОстаток <> 0)
В этом случае мы отсекаем не только тех, кто совершал сделки в указанном периоде, но и тех, у кого на конец периода осталось незакрытое сальдо.
Таким образом, комбинируя работу с виртуальными таблицами регистров накопления и правильные типы соединений в запросах, мы получаем гибкий инструмент для очистки и анализа клиентской базы в 1С:УТ 10.3.