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