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