При разработке отчетов в Системе компоновки данных (СКД) часто возникает ситуация, когда одно поле может содержать данные разных типов. Например, в зависимости от вида документа в колонку выводится либо Склад (Справочник.СтруктурныеЕдиницы), либо Покупатель (Справочник.Контрагенты). По умолчанию СКД предлагает пользователю сначала выбрать тип данных, а затем уже конкретное значение. Это создает лишние клики и путаницу. Рассмотрим, как сделать интерфейс профессиональным и удобным, разделив отборы по типам.
Проанализируем самый гибкий и правильный с точки зрения платформы 1С метод — использование расширения языка запросов. Этот способ позволяет добавить в список доступных полей отбора виртуальные поля, которые будут жестко типизированы. Разберем этот подход на примере.
Предположим, у нас есть составное поле, которое формируется в зависимости от регистратора. Чтобы СКД понимала, что мы хотим фильтровать данные отдельно по контрагенту и отдельно по складу, мы используем конструкцию ВЫРАЗИТЬ внутри блока ГДЕ, заключенного в фигурные скобки.
Рассмотрим пример кода в тексте запроса СКД:
ВЫБРАТЬ
ПродажиОбороты.Регистратор КАК Регистратор,
ВЫБОР
КОГДА ПродажиОбороты.Регистратор ССЫЛКА Документ.ОтчетКомиссионера
ТОГДА ВЫРАЗИТЬ(ПродажиОбороты.Регистратор КАК Документ.ОтчетКомиссионера).Контрагент
ИНАЧЕ ВЫРАЗИТЬ(ПродажиОбороты.Регистратор КАК Документ.РасходнаяНакладная).СтруктурнаяЕдиница
КОНЕЦ КАК Продавец
ИЗ
РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты
{ГДЕ
(ВЫРАЗИТЬ(ВЫБОР
КОГДА ПродажиОбороты.Регистратор ССЫЛКА Документ.ОтчетКомиссионера
ТОГДА ПродажиОбороты.Регистратор.Контрагент
ИНАЧЕ ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
КОНЕЦ КАК Справочник.Контрагенты)).* КАК Отбор_Покупатель,
(ВЫРАЗИТЬ(ВЫБОР
КОГДА ПродажиОбороты.Регистратор ССЫЛКА Документ.РасходнаяНакладная
ТОГДА ПродажиОбороты.Регистратор.СтруктурнаяЕдиница
ИНАЧЕ ЗНАЧЕНИЕ(Справочник.СтруктурныеЕдиницы.ПустаяСсылка)
КОНЕЦ КАК Справочник.СтруктурныеЕдиницы)).* КАК Отбор_Склад}
Что дает этот подход? Во-первых, в настройках отчета появятся два отдельных поля: Отбор_Покупатель и Отбор_Склад. Во-вторых, благодаря ВЫРАЗИТЬ, при нажатии на кнопку выбора значения система сразу откроет нужный справочник, не спрашивая тип данных. В-третьих, конструкция .* позволяет пользователю выбирать не только саму ссылку, но и обращаться к реквизитам этих объектов в отборе (например, Отбор_Покупатель.ИНН).
Проанализируем ситуацию, когда необходимо использовать параметры вместо стандартных отборов. Это бывает полезно, если логика условий в запросе слишком сложна для автоматического расширения ГДЕ. В этом случае мы создаем два параметра на закладке Параметры в СКД: &Покупатель и &Склад.
Выясним причину, по которой обычное условие может выдавать ошибку. Если мы просто напишем ГДЕ Поле = &Параметр, и параметр не будет заполнен, запрос вернет пустой результат или ошибку. Поэтому нам нужно предусмотреть проверку на заполненность. Рассмотрим правильный вариант условия в запросе:
ГДЕ (&Покупатель = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
ИЛИ ПродажиОбороты.Регистратор.Контрагент = &Покупатель)
И (&Склад = ЗНАЧЕНИЕ(Справочник.СтруктурныеЕдиницы.ПустаяСсылка)
ИЛИ ПродажиОбороты.Регистратор.СтруктурнаяЕдиница = &Склад)
Чтобы форма выбора открывалась корректно, на закладке Параметры для каждого параметра в колонке Тип необходимо указать конкретный справочник (снять галочку Составной тип). Также важно в свойствах параметров установить флаг Использовать всегда, чтобы условие в запросе отрабатывало стабильно.
Рассмотрим еще один интересный метод, который позволяет "обмануть" систему и заставить ее предлагать нужные типы. Мы можем добавить в ВЫБРАТЬ пустые поля с принудительным приведением типа, которые не будем выводить в отчет, но будем использовать в отборах.
Посмотрим на пример такого кода:
ВЫБРАТЬ
ПродажиОбороты.Регистратор КАК Регистратор,
ПродажиОбороты.СуммаОборот КАК Сумма,
ВЫРАЗИТЬ(NULL КАК Справочник.Контрагенты) КАК ПолеДляОтбораПокупатель,
ВЫРАЗИТЬ(NULL КАК Справочник.СтруктурныеЕдиницы) КАК ПолеДляОтбораСклад
ИЗ
РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты
Затем на закладке Настройки в СКД мы переносим эти поля в список доступных полей отбора. В условии запроса или в настройках характеристик мы связываем эти "пустышки" с реальной логикой фильтрации. Однако этот метод чаще используется в сочетании с механизмом характеристик или программной обработкой компоновки.
Проанализируем важный технический нюанс, упомянутый опытными разработчиками. Использование конструкций вида ПродажиОбороты.Регистратор.Контрагент в условиях ГДЕ или в блоке ВЫБОР крайне нежелательно. Посмотрим, почему это так.
Почему нельзя обращаться через точку от Регистратора:
LEFT JOIN ко всем таблицам документов, которые являются регистраторами данного регистра. Если в базе сотни видов документов, производительность упадет в разы.ВЫРАЗИТЬ(ПродажиОбороты.Регистратор КАК Документ.ВашВидДокумента).Контрагент. Это заставляет платформу обращаться только к одной конкретной таблице.Если вам необходимо, чтобы отборы работали одновременно и по складу, и по контрагенту (логика ИЛИ), рекомендуется переписать запрос с использованием ОБЪЕДИНИТЬ ВСЕ. Рассмотрим структуру такого запроса:
ВЫБРАТЬ
Продажи.Регистратор,
Продажи.Регистратор.Контрагент КАК Продавец,
"Контрагент" КАК ТипПродавца
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Регистратор ССЫЛКА Документ.ОтчетКомиссионера
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Продажи.Регистратор,
Продажи.Регистратор.СтруктурнаяЕдиница,
"Склад"
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Регистратор ССЫЛКА Документ.РасходнаяНакладная
Такой подход позволяет наложить независимые условия на каждую часть объединения, что значительно ускоряет выполнение отчета на больших объемах данных.
После того как мы подготовили запрос, разберем, как сделать работу пользователя максимально комфортной:
Отбор_Покупатель).Таким образом, мы создали чистый и понятный интерфейс, где для каждой задачи (отбор по складу или покупателю) есть свое поле с мгновенным переходом к нужному справочнику.