Как правильно исключить клиентов с определенным пакетом из сегмента в 1С?

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

Часто при работе с конфигурациями вроде «1С:Фитнес клуб» или «1С:Управление торговлей» возникает задача сформировать сегмент клиентов с определенными условиями. Однако, когда мы пытаемся исключить клиентов, у которых есть конкретная услуга или пакет (например, «Акционный массаж»), используя стандартный отбор Не равно, система ведет себя неочевидно: клиенты с этим пакетом все равно попадают в сегмент, а клиенты без пакетов вообще исчезают. Разберем по шагам, почему так происходит, и рассмотрим рабочие способы решения этой задачи.

Почему стандартное условие «Не равно» не работает?

Проблема кроется в математике запросов и логике работы Системы компоновки данных (СКД) с коллекциями (табличными частями документов или записями подчиненных регистров). Выясним причину такого поведения.

Когда в СКД мы устанавливаем отбор вида Пакет <> "Акционный массаж", система проверяет: есть ли у клиента хотя бы одна запись, которая удовлетворяет этому условию.

  1. Сценарий 1: У клиента несколько разных пакетов. Допустим, у Иванова И.И. куплены пакеты «Плавание» и «Массаж». Система анализирует список его услуг, видит пакет «Плавание», понимает, что он не равен «Массажу», и считает, что условие отбора выполнено. В результате клиент включается в сегмент, несмотря на наличие массажа.
  2. Сценарий 2: У клиента вообще нет пакетов. Если клиент ничего не покупал, поле пакета в базе данных содержит пустое значение NULL. Сравнение NULL <> "Массаж" возвращает ложь. Из-за этого клиенты, у которых пакеты отсутствуют в принципе, полностью выпадают из сегмента.

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

Решение 1: Вычитание сегментов (пользовательский режим)

Самый надежный и правильный метод, который не требует навыков программирования и доработки конфигурации, — это пересечение (или вычитание) сегментов. Механизм сегментации специально задуман так, чтобы сложные отборы по коллекциям не пытались уместить в один фильтр.

Разберем этот метод по шагам:

  1. Создание вспомогательного сегмента. Сначала создадим сегмент, который соберет всех «неугодных» клиентов. Назовем его, например, «Имеют пакет Акционный массаж». В отборе этого сегмента установим простое и понятное условие: Пакет = "Акционный массаж 3 штуки". Сформируем сегмент.
  2. Создание основного рабочего сегмента. Теперь создадим тот сегмент, который нам изначально был нужен. Настроим в нем все базовые условия отбора (пол, возраст, сумма покупок и т.д.).
  3. Настройка исключения. Чтобы убрать из основного сегмента тех, кто попал во вспомогательный, добавим условие принадлежности к сегменту. В отборах выберем поле Сегмент (или Входит в сегмент), установим вид сравнения Не равно (или Не в списке) и укажем наш вспомогательный сегмент.

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

Решение 2: Доработка схемы СКД (для разработчика)

Если специфика бизнес-процесса требует, чтобы пользователи могли делать такие отборы в одном сегменте без создания вспомогательных, придется вмешаться в конфигурацию. Проанализируем варианты доработки набора данных в СКД.

1. Использование оператора «НЕ В» (NOT IN)

В тексте запроса набора данных можно исключить саму ссылку на клиента с помощью вложенного запроса. Это жестко отсечет клиента целиком, даже если у него есть десяток других пакетов.


ВЫБРАТЬ
    СправочникКлиенты.Ссылка КАК Клиент
ИЗ
    Справочник.Клиенты КАК СправочникКлиенты
ГДЕ
    СправочникКлиенты.Ссылка НЕ В (
        ВЫБРАТЬ 
            ТаблицаХраненияПакетов.Клиент 
        ИЗ 
            РегистрСведений.ПакетыКлиентов КАК ТаблицаХраненияПакетов 
        ГДЕ 
            ТаблицаХраненияПакетов.Пакет = &ИсключаемыйПакет
    )

2. Корректная обработка отсутствия пакетов (NULL)

Чтобы не терялись люди без пакетов при левых соединениях таблиц, в условиях СКД необходимо обрабатывать значения NULL с помощью функции ЕСТЬ NULL.


ГДЕ 
    (ТаблицаПакетов.Пакет ЕСТЬ NULL 
    ИЛИ ТаблицаПакетов.Пакет <> &ИсключаемыйПакет)

Важно: этот кусок кода не решает проблему наличия нескольких пакетов одновременно, но спасает от потери пустых клиентов.

3. Отбор по группировке с агрегатной функцией

Это красивый и эффективный метод прямо в настройках СКД. Мы можем подсчитать количество «нежелательных» пакетов у каждого клиента, и если оно больше нуля — исключать его.

  1. Создадим вычисляемое поле в СКД, назовем его КоличествоМассажей.
  2. В выражении поля напишем: СУММА(ВЫБОР КОГДА Пакет = &Массаж ТОГДА 1 ИНАЧЕ 0 КОНЕЦ).
  3. В настройках сегмента (или отчета) перейдем на вкладку «Отбор».
  4. Установим отбор не для детальных записей, а для группировки по клиенту: КоличествоМассажей = 0.

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

Используя эти методы, вы сможете гибко управлять списками клиентов в 1С и обходить ограничения стандартных алгоритмов СКД при работе с вложенными коллекциями данных.

← На главную