Как в СКД настроить один отбор сразу по двум полям с логикой ИЛИ?

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

При разработке отчетов на Системе Компоновки Данных (СКД) мы часто сталкиваемся с ситуацией, когда данные хранятся в двух разных полях, но по смыслу они однородны. Классический пример, который мы сегодня разберем: отчет по движениям товаров, где есть СкладРасхода (откуда ушло) и СкладПрихода (куда пришло).

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

Постановка задачи

Допустим, у нас есть запрос к регистру накопления или оборотному регистру. В выборке присутствуют два поля:

  1. СкладРасхода (или СкладОтправитель)
  2. СкладПрихода (или СкладПолучатель)

Нам необходимо организовать отбор так, чтобы условие звучало следующим образом:

(СкладРасхода = ЗначениеОтбора) ИЛИ (СкладПрихода = ЗначениеОтбора)

Способ 1. Использование Параметра и Группы ИЛИ в настройках (Базовый метод)

Это самое надежное и "штатное" решение, которое предлагает платформа. Давайте разберем его по шагам.

Шаг 1. Подготовка запроса

В самом запросе ничего необычного писать не нужно, достаточно просто выбрать необходимые поля. Однако, для удобства дальнейшей настройки, мы создадим параметр данных, который будет хранить значение нашего "единого склада".

Перейдем на закладку Параметры в схеме компоновки данных и добавим новый параметр:

Шаг 2. Настройка отбора

Теперь перейдем на закладку Настройки. Здесь нам нужно сконструировать логическое условие. Если мы просто добавим два отбора подряд, СКД соединит их через логическое И, и мы получим пустой результат (так как склад не может быть одновременно и отправителем, и получателем в одной записи, если это не перемещение на самого себя).

Действуем следующим образом:

  1. В окне настроек переходим на вкладку Отбор.
  2. Добавляем не новый элемент, а Группу ИЛИ. Для этого нажимаем кнопку добавления и выбираем "Группа ИЛИ". Это скажет системе, что должно выполняться хотя бы одно условие внутри группы.
  3. Внутри этой группы создаем первый элемент отбора:
    • Левое значение: СкладРасхода
    • Вид сравнения: Равно
    • Правое значение: Здесь важно! Нажмите на кнопку "Т" (тип значения) или крестик очистки, затем выберите тип Поле компоновки данных. В списке полей найдите папку "Параметры" и выберите наш параметр ВыбСклад.
  4. Внутри той же группы создаем второй элемент отбора:
    • Левое значение: СкладПрихода
    • Вид сравнения: Равно
    • Правое значение: Аналогично выбираем параметр ВыбСклад.

В результате в настройках у вас должна получиться такая структура:


Группа ИЛИ
    СкладРасхода Равно Параметры.ВыбСклад
    СкладПрихода Равно Параметры.ВыбСклад

Шаг 3. Визуализация для пользователя

В теме на форуме автор справедливо заметил: "выглядит странно". Действительно, стандартно параметры отображаются отдельно от отборов. Чтобы привести интерфейс к единообразию ("Организация", "Номенклатура", "Склад"), сделаем следующее:

  1. Перейдите на вкладку Настройки.
  2. Внизу выберите вкладку Параметры данных.
  3. Найдите ваш параметр ВыбСклад.
  4. В правой части (свойства элемента пользовательских настроек) поставьте галочку Включать в пользовательские настройки.
  5. Режим редактирования можно выбрать Быстрый доступ (тогда поле появится прямо в шапке отчета) или Обычный (будет в кнопке "Настройки").

Таким образом, пользователь будет видеть просто поле "Склад (для отбора)", а сложная логика с группой "ИЛИ" будет скрыта внутри схемы.

Способ 2. Программный перехват настроек (Продвинутый метод)

Иногда требования к интерфейсу очень строгие: параметр использовать нельзя, должен быть именно "Отбор" в стандартной таблице отборов. Но стандартный отбор работает только по принципу "Поле — Значение".

В этом случае мы можем пойти на хитрость: дать пользователю настроить "фейковый" отбор, а при формировании отчета программно подменить его на нашу конструкцию с "ИЛИ".

Алгоритм действий:

  1. В схеме компоновки создаем вычисляемое поле или просто используем одно из полей (например, СкладРасхода), переименовав его в заголовке просто в "Склад".
  2. Пользователь устанавливает отбор: Склад Равно СкладОсновной.
  3. В модуле объекта отчета переопределяем событие ПриКомпоновкеРезультата.

Рассмотрим пример кода, который реализует эту логику:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь; // Сами будем компоновать
    
    // Получаем текущие настройки пользователя
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    
    // Ищем отбор по полю "Склад" (допустим, мы договорились, что пользователь фильтрует по СкладРасхода)
    ИскомоеПоле = Новый ПолеКомпоновкиДанных("СкладРасхода");
    НайденныйОтбор = Неопределено;
    ЗначениеОтбора = Неопределено;
    
    // Перебор элементов отбора для поиска установленного пользователем значения
    Для Каждого ЭлементОтбора Из Настройки.Отбор.Элементы Цикл
        Если ТипЗнч(ЭлементОтбора) = Тип("ЭлементОтбораКомпоновкиДанных") 
           И ЭлементОтбора.ЛевоеЗначение = ИскомоеПоле 
           И ЭлементОтбора.Использование Тогда
            
            НайденныйОтбор = ЭлементОтбора;
            ЗначениеОтбора = ЭлементОтбора.ПравоеЗначение;
            Прервать;
            
        КонецЕсли;
    КонецЦикла;
    
    // Если пользователь установил отбор, модифицируем настройки
    Если НайденныйОтбор <> Неопределено И ЗначениеОтбора <> Неопределено Тогда
        
        // Удаляем простой отбор, который поставил пользователь
        Настройки.Отбор.Элементы.Удалить(НайденныйОтбор);
        
        // Создаем Группу ИЛИ
        ГруппаИли = Настройки.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
        ГруппаИли.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИли;
        ГруппаИли.Использование = Истина;
        
        // Добавляем условие по Складу Расхода
        ЭлементРасхода = ГруппаИли.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        ЭлементРасхода.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("СкладРасхода");
        ЭлементРасхода.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
        ЭлементРасхода.ПравоеЗначение = ЗначениеОтбора;
        ЭлементРасхода.Использование = Истина;
        
        // Добавляем условие по Складу Прихода
        ЭлементПрихода = ГруппаИли.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        ЭлементПрихода.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("СкладПрихода");
        ЭлементПрихода.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
        ЭлементПрихода.ПравоеЗначение = ЗначениеОтбора;
        ЭлементПрихода.Использование = Истина;
        
    КонецЕсли;
    
    // Выполняем компоновку с модифицированными настройками
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

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

Способ 3. Изменение текста запроса (UNION ALL)

Существует еще один подход — кардинально изменить структуру данных на уровне запроса. Мы можем "свернуть" два поля в одно с помощью объединения.

Идея следующая: выбираем данные дважды.

  1. Первый раз выбираем СкладРасхода и называем его ОбщийСклад.
  2. Второй раз выбираем СкладПрихода и тоже называем его ОбщийСклад.
  3. Объединяем эти выборки через ОБЪЕДИНИТЬ ВСЕ.

Пример запроса:


ВЫБРАТЬ
    Запасы.СкладРасхода КАК ОбщийСклад,
    Запасы.Номенклатура,
    Запасы.Количество,
    "Расход" КАК ТипДвижения
ИЗ
    РегистрНакопления.Запасы КАК Запасы
ГДЕ
    Запасы.СкладРасхода <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    Запасы.СкладПрихода,
    Запасы.Номенклатура,
    Запасы.Количество,
    "Приход"
ИЗ
    РегистрНакопления.Запасы КАК Запасы
ГДЕ
    Запасы.СкладПрихода <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)

Преимущества:

Недостатки:

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

Вывод

Для решения задачи фильтрации по двум полям (ИЛИ) наиболее оптимальным и безопасным является Способ 1 (Параметр + Группа ИЛИ в настройках). Он не требует написания кода и корректно обрабатывается платформой. Чтобы не смущать пользователя, просто выведите этот параметр в "Быстрый доступ" пользовательских настроек, дав ему понятное имя.

← На главную