При работе с типовыми конфигурациями на платформе «1С:Предприятие 8» (такими как «1С:ERP Управление предприятием», «1С:Комплексная автоматизация» или «1С:Управление торговлей») пользователи и аналитики часто сталкиваются со странным поведением отчетов. Типичный пример: необходимо построить отчет по задолженности клиентов, исключив из него определенную группу — например, безнадежных должников, которые были вручную объединены в сегмент «Должники».
Логичным действием кажется установка в настройках отчета простого фильтра: Сегмент партнеров — Не равно — Должники. Однако на практике такой отбор не срабатывает: отчет продолжает выводить абсолютно всех контрагентов, включая тех, кто входит в исключаемый сегмент. При этом отбор на равенство (Равно) отрабатывает безупречно. Выясним техническую причину этой проблемы и подробно разберем несколько эффективных способов ее решения.
Для того чтобы понять природу этой ошибки, проанализируем внутреннее устройство механизма сегментации в типовых решениях 1С. Запрос стандартного отчета не обращается напрямую к справочнику Партнеры с проверкой их сегментов «на лету». Вместо этого Система компоновки данных (СКД) использует оптимизированный алгоритм связи с регистром сведений ПартнерыСегмента.
При формировании отчета СКД выполняет следующие действия:
РегистрСведений.ПартнерыСегмента и выбирает из него всех партнеров, которые соответствуют заданному условию. Полученный массив данных сохраняется во временную таблицу (например, ВТ_ОтборПоСегменту).Когда мы пытаемся применить условие Сегмент НЕ РАВЕН "Должники", этот стройный алгоритм приводит к двум критическим логическим ошибкам:
ПартнерыСегмента полностью отсутствуют. При формировании временной таблицы отбора система просто «не знает» о существовании такого клиента. В результате клиент без сегментов вообще не попадает во временную таблицу и полностью исчезает из отчета. Отчет покажет только тех клиентов, у которых назначен хотя бы какой-то другой сегмент (например, «Оптовики» или «VIP»).Сегмент <> "Должники" СКД обнаружит в регистре строку, связывающую этого клиента с сегментом «VIP». Данное условие выполнится, партнер запишется во временную таблицу отбора и, как результат, преспокойно отобразится в итоговом отчете, проигнорировав свое присутствие в сегменте «Должники».Именно из-за этих архитектурных особенностей разработчики фирмы «1С» закладывали использование отборов по сегментам в СКД исключительно на равенство (операторы Равно или В списке). Любые попытки инвертировать отбор стандартными средствами настройки компоновки обречены на неудачу.
Рассмотрим детально, как обойти эту проблему без изменения кода конфигурации.
---
Поскольку механизм СКД безошибочно работает с условием Равно, мы можем решить задачу от обратного. Для этого нам необходимо создать новый сегмент, который будет включать только «разрешенных» для вывода в отчет клиентов.
Разберем этот процесс по шагам:
Клиенты без безнадежных долгов.Периодически обновлять или Формировать динамически.Партнер.Ссылка НЕ В ИЕРАРХИИ (Сегмент "Должники") или использовать встроенный механизм исключения сегментов в настройках компоновки правила сегмента.Сегмент клиентов — Равно — Клиенты без безнадежных долгов.Данный метод абсолютно надежен, не требует программирования и работает на стандартных механизмах платформы.
---
Сегменты в концепции ERP-систем представляют собой динамические маркетинговые списки. Для фиксации статических системных признаков клиентов (таких как запрет на отгрузку, статус надежности или необходимость исключения из отчетности) гораздо правильнее использовать дополнительные реквизиты.
Посмотрим, как быстро настроить этот функционал:
Партнеры (или Контрагенты) и добавим для него новый дополнительный реквизит.Исключить из отчетов по задолженности. Тип значения выберем Булево (Да/Нет).Да.Клиент (или Партнер) найдем наш дополнительный реквизит: Партнер.[Исключить из отчетов по задолженности].Равно — Нет.Поскольку дополнительный реквизит является свойством самого объекта базы данных (а не элементом стороннего регистра сведений с уникальными связями), СКД при таком отборе корректно обработает значения NULL (когда реквизит не заполнен вовсе). В отчет попадут все клиенты, кроме тех, у кого флаг установлен принудительно.
---
Проанализируем ситуацию с точки зрения ведения бухгалтерского и управленческого учета. Если клиенты из списка «никогда не вернут долги», то отражение этих сумм в качестве активной дебиторской задолженности искажает реальную финансовую картину предприятия (активы компании выглядят переоцененными).
Наиболее правильным решением будет официальное признание долга безнадежным и его последующее списание:
Списание дебиторской задолженности.После проведения документа баланс взаиморасчетов с данными контрагентами обнулится. Они автоматически перестанут выводиться в любых отчетах по задолженности, без необходимости настраивать сложные фильтры и поддерживать актуальность ручных сегментов.
---
Если по каким-то причинам бизнес-логика требует использовать именно отрицание по сегментам во многих отчетах сразу, и ручная настройка обходных путей не подходит, мы можем прибегнуть к программной корректировке.
Чтобы сохранить конфигурацию на поддержке, создадим расширение. Нам потребуется переопределить обработку компоновки данных. Типовой общий модуль, отвечающий за подготовку отчетов перед выводом (например, КомпоновкаДанныхКлиентСервер или специализированные модули отчетов), содержит процедуры формирования текстов запросов СКД.
Мы можем перехватить процедуру компоновки и программно заменить стандартный отбор по сегменту на конструкцию вида:
// Пример модификации отбора в процедуре ПриКомпоновкеРезультата
Для Каждого ЭлементОтбора Из КомпоновщикНастроек.Настройки.Отбор.Элементы Цикл
Если ТипЗнч(ЭлементОтбора) = Тип("ЭлементОтбораКомпоновкиДанных")
И ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Партнер.Сегмент")
И ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.НеРавно Тогда
// Перестраиваем логику отбора на использование отрицания вхождения в список
ЭлементОтбора.Использование = Ложь;
НовыйОтбор = КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
НовыйОтбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Партнер");
НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.НеВСписке;
НовыйОтбор.ПравоеЗначение = ПолучитьМассивПартнеровСегмента(ЭлементОтбора.ПравоеЗначение);
НовыйОтбор.Использование = Истина;
КонецЕсли;
КонецЦикла;
Вспомогательная функция ПолучитьМассивПартнеровСегмента() должна возвращать массив ссылок клиентов, состоящих в указанном сегменте. Таким образом, СКД получит простой и понятный массив исключений, который отработает быстро и без логических сбоев.
Мы подробно разобрали, почему стандартный функционал отчетов 1С блокирует корректную работу отрицающих условий для сегментов. Наиболее быстрым и не требующим программирования решением является создание инвертированного сегмента (Решение 1) или использование дополнительных реквизитов (Решение 2). С точки зрения методологии учета лучшим решением всегда будет своевременное списание невозвратных долгов (Решение 3).