Как реализовать гибкий отбор номенклатуры с выбором вида сравнения в произвольной обработке 1С на управляемых формах (УТ 11)?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке обработок в системе 1С:Предприятие 8.3 на управляемых формах часто возникает потребность в создании удобного и гибкого механизма отбора данных, аналогичного тому, что мы видим в отчетах, построенных на Системе Компоновки Данных (СКД). Стандартные подходы, такие как заполнение таблицы значений для отбора, могут быть громоздкими и неудобными для пользователей, особенно если требуется выбирать не только конкретные значения, но и различные виды сравнения (например, "Равно", "В списке", "Содержит"). В этой статье мы подробно рассмотрим, как реализовать такой гибкий отбор для справочника "Номенклатура" в произвольной обработке на управляемых формах в конфигурации "Управление торговлей 11" (УТ 11).

Основная задача заключается в том, чтобы предоставить пользователю возможность выбирать вид сравнения и значение для отбора по полю "Номенклатура" без необходимости каждый раз указывать само поле. Мы достигнем этого, интегрировав функционал СКД непосредственно в форму нашей обработки.

Суть проблемы и желаемый результат

Представим, что у нас есть обработка, которая выполняет определенные действия с номенклатурой. Изначально отбор номенклатуры реализован через таблицу значений, куда пользователь вручную добавляет нужные элементы. Такой подход имеет ряд недостатков:

  1. Ограниченность: Пользователь может отобрать только по прямому равенству ссылок.
  2. Неудобство: Каждый раз нужно добавлять каждый элемент по отдельности.

Мы хотим изменить этот подход, сделав отбор похожим на стандартный отбор в отчетах СКД. Это означает, что пользователь должен видеть два поля: одно для выбора вида сравнения (например, "Равно", "В списке", "Больше", "Содержит") и второе для ввода значения (или значений). При этом поле, по которому ведется отбор, должно быть фиксировано — это всегда будет "Номенклатура".

Ключевое решение: Использование Системы Компоновки Данных (СКД) на форме

Наиболее эффективным и рекомендуемым способом решения этой задачи является использование объекта КомпоновщикНастроекКомпоновкиДанных (КНКД) в сочетании с предварительно сконфигурированной Схемой Компоновки Данных. Давайте разберем этот процесс по шагам.

Шаг 1: Создание макета СКД в вашей обработке

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

  1. Откройте обработку: Перейдите в конфигуратор, найдите вашу обработку и откройте ее.
  2. Создайте макет: Добавьте новый макет к вашей обработке. Установите тип макета "Схема компоновки данных". Назовем его, например, "МакетСКДОтоборНоменклатуры".
  3. Сконфигурируйте схему СКД: Откройте конструктор схемы компоновки данных.
    • Наборы данных: Добавьте новый набор данных типа "Запрос". В качестве запроса мы будем использовать простой запрос к справочнику "Номенклатура".
    • 
      ВЫБРАТЬ
          Номенклатура.Ссылка КАК Номенклатура
      ИЗ
          Справочник.Номенклатура КАК Номенклатура
      

      Этот запрос выбирает ссылки на элементы справочника "Номенклатура" и представляет их под псевдонимом "Номенклатура".

    • Поля: Перейдите на вкладку "Поля". Убедитесь, что поле "Номенклатура" (или "Ссылка" из Номенклатуры) присутствует в списке доступных полей.
    • Настройки: Перейдите на вкладку "Настройки". Здесь нам нужно определить, что поле "Номенклатура" будет доступно для отбора.
      • Добавьте новую настройку, например, "Основная".
      • В этой настройке перейдите в "Отбор" и добавьте новый элемент отбора. В качестве поля отбора выберите "Номенклатура". Важно: Вы можете сразу установить флажок "Использование" для этого поля в схеме СКД, но не заполнять его значение. Это позволит системе автоматически создать строку отбора по номенклатуре на форме, которую пользователь затем сможет редактировать.

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

Шаг 2: Добавление реквизита на форму обработки

Теперь нам нужно связать нашу форму с этой схемой СКД. Для этого мы добавим специальный реквизит на форму.

  1. Откройте форму обработки: В дереве объектов конфигурации откройте форму вашей обработки.
  2. Добавьте реквизит формы: В окне "Реквизиты" формы добавьте новый реквизит.
    • Имя: Например, "КомпоновщикНастроекОтбора".
    • Тип: Выберите тип КомпоновщикНастроекКомпоновкиДанных.

Шаг 3: Размещение элемента отбора на форме

После добавления реквизита типа КомпоновщикНастроекКомпоновкиДанных на форму, мы можем вытащить его интерфейс отбора непосредственно в элементы формы.

  1. Перейдите на вкладку "Элементы" формы.
  2. Создайте новую группу: Желательно создать отдельную группу для отбора, например, с видом "Обычная группа", чтобы аккуратно разместить элементы.
  3. Перетащите свойство "Отбор": Из окна "Реквизиты" формы найдите ваш реквизит "КомпоновщикНастроекОтбора". Раскройте его свойства и найдите "Настройки", а затем "Отбор". Перетащите этот элемент "Отбор" на форму в созданную группу.

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

Шаг 4: Инициализация КомпоновщикаНастроекКомпоновкиДанных при создании формы

Чтобы наш элемент отбора заработал, его необходимо инициализировать при создании формы на сервере, загрузив в него нашу схему СКД.

  1. Создайте обработчик события: Перейдите на вкладку "События" формы и создайте обработчик для события ПриСозданииНаСервере.
  2. Напишите код инициализации: В этом обработчике мы выполним следующие действия:
    • Получим нашу схему компоновки данных из макета обработки.
    • Инициализируем реквизит КомпоновщикНастроекОтбора, передав ему схему как источник доступных настроек.
    • Загрузим стандартные настройки из схемы (если они там были).

Пример кода для процедуры ПриСозданииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    // 1. Получаем схему компоновки данных из макета обработки
    СхемаКомпоновкиДанных = ПолучитьМакет("МакетСКДОтоборНоменклатуры");
    
    // 2. Инициализируем компоновщик настроек отбора
    // Создаем источник доступных настроек на основе нашей схемы
    ИсточникДоступныхНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновкиДанных);
    КомпоновщикНастроекОтбора.Инициализировать(ИсточникДоступныхНастроек);
    
    // 3. Загружаем настройки по умолчанию из схемы
    // Это позволяет, например, загрузить уже существующий элемент отбора по "Номенклатуре",
    // если он был добавлен в макете СКД
    КомпоновщикНастроекОтбора.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);

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

КонецПроцедуры

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

Шаг 5: Получение и применение отбора в запросе

Теперь, когда пользователь настроил отбор, нам нужно получить эти настройки и применить их к нашим данным. Есть два основных способа это сделать:

Вариант А: Использование ПроцессораКомпоновкиДанных для выполнения всего запроса

Если ваша основная логика получения данных также может быть реализована с помощью СКД, то самый простой способ — использовать объект ПроцессорКомпоновкиДанных. Он примет вашу схему и пользовательские настройки, выполнит запрос и вернет результат.

  1. Создайте команду на форме: Например, кнопка "Сформировать".
  2. Напишите обработчик команды: В нем мы получим текущие настройки отбора из нашего КомпоновщикНастроекОтбора.

Пример кода для обработчика команды "Сформировать":


&НаКлиенте
Процедура Сформировать(Команда)
    // Вызываем серверную процедуру для выполнения запроса с отбором
    РезультатЗапроса = ПолучитьДанныеСОтборомНаСервере();
    // Далее работаем с РезультатЗапроса (например, выводим в таблицу на форме)
КонецПроцедуры

&НаСервере
Функция ПолучитьДанныеСОтборомНаСервере()
    
    // 1. Получаем текущие настройки компоновщика
    НастройкиКомпоновки = КомпоновщикНастроекОтбора.ПолучитьНастройки();
    
    // 2. Получаем схему компоновки данных
    СхемаКомпоновкиДанных = ПолучитьМакет("МакетСКДОтоборНоменклатуры");
    
    // 3. Создаем Компоновщик Макета Компоновки Данных
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    
    // 4. Создаем Макет Компоновки Данных на основе схемы и настроек
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновки);
    
    // 5. Создаем Процессор Компоновки Данных
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки,, Истина); // Истина - для использования внешних наборов данных, если есть
    
    // 6. Создаем Процессор Вывода Результата Компоновки Данных в коллекцию значений
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    ТаблицаРезультат = Новый ТаблицаЗначений;
    ПроцессорВывода.УстановитьОбъект(ТаблицаРезультат);
    
    // 7. Выводим результат
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    Возврат ТаблицаРезультат;
    
КонецФункции

В этом случае ТаблицаРезультат будет содержать данные, уже отфильтрованные согласно пользовательским настройкам. Это самый простой способ, если ваш основной запрос также может быть описан в СКД.

Вариант Б: Программное формирование условия запроса на основе отбора СКД

Если ваш основной запрос является сложным и выполняется вручную (не через СКД), вы можете программно проанализировать объект отбора из КНКД и сформировать условие для вашего запроса.

  1. Получите элементы отбора: Из объекта КомпоновщикНастроекОтбора.Настройки.Отбор.Элементы вы можете получить список всех установленных пользователем условий.
  2. Итерируйте по элементам: Для каждого элемента отбора вы можете получить его ЛевоеЗначение (поле), ВидСравнения и ПравоеЗначение (значение).
  3. Сформируйте условие `ГДЕ`: На основе этих данных динамически постройте строку условия для вашего запроса.

Рассмотрим пример формирования условия для запроса:


&НаСервере
Функция ПолучитьУсловиеОтбораНоменклатуры()

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

            Иначе
                // Обработка неподдерживаемых видов сравнения или вывод ошибки
        КонецВыбора;
        
    КонецЦикла;
    
    Возврат Новый Структура("ТекстУсловия, ПараметрыЗапроса", ТекстУсловия, ПараметрыЗапроса);

КонецФункции

&НаСервере
Функция ВыполнитьСвойЗапросСОтборомНаСервере()
    
    СформированноеУсловие = ПолучитьУсловиеОтбораНоменклатуры();
    ТекстУсловия = СформированноеУсловие.ТекстУсловия;
    ПараметрыЗапроса = СформированноеУсловие.ПараметрыЗапроса;
    
    ТекстЗапроса = "ВЫБРАТЬ
        | Номенклатура.Ссылка КАК Номенклатура,
        | Номенклатура.Наименование КАК Наименование
        |ИЗ
        | Справочник.Номенклатура КАК Номенклатура";
        
    Если Не ТекстУсловия = "" Тогда
        ТекстЗапроса = ТекстЗапроса + " ГДЕ " + ТекстУсловия;
    КонецЕсли;
    
    Запрос = Новый Запрос(ТекстЗапроса);
    Для Каждого Параметр Из ПараметрыЗапроса Цикл
        Запрос.УстановитьПараметр(Параметр.Ключ, Параметр.Значение);
    КонецЦикла;
    
    Возврат Запрос.Выполнить().Выгрузить();
    
КонецФункции

Функция ПолучитьУсловиеОтбораНоменклатуры() возвращает структуру, содержащую строку условия для запроса и соответствие с параметрами, которые необходимо установить для запроса. Затем эта структура используется в вашей основной функции выполнения запроса.

Особенности для отбора только по "Номенклатуре"

Для того чтобы пользователь не выбирал поле отбора, а сразу работал с видом сравнения и значением для "Номенклатуры", мы предприняли несколько шагов:

  1. Схема СКД: В макете СКД мы определили только поле "Номенклатура" как потенциальное поле для отбора. Если вы хотите быть абсолютно уверенными, что пользователь не сможет добавить другие поля, вы можете управлять этим через настройки КНКД программно, например, отключив возможность добавления новых элементов отбора или ограничивая список доступных полей.
  2. Инициализация: В процедуре ПриСозданииНаСервере мы добавили логику, которая при отсутствии элементов отбора, принудительно создает элемент отбора по "Номенклатуре" и делает его активным (Использование = Истина). Это гарантирует, что пользователь всегда начнет работу с уже готовой строкой отбора по "Номенклатуре".

Интерфейс СКД автоматически предоставит поля для выбора вида сравнения (выпадающий список) и ввода значения (обычно поле ввода или поле выбора, в зависимости от типа данных поля "Номенклатура").

Преимущества данного подхода

  1. Гибкость: Пользователь получает широкий спектр видов сравнения.
  2. Стандартный интерфейс: Привычный и понятный интерфейс, как в стандартных отчетах 1С.
  3. Минимальная доработка: Не требуется сложный код для отрисовки полей отбора, все предоставляется СКД.
  4. Сохранение настроек: При желании, вы можете реализовать сохранение настроек отбора пользователя, используя стандартные механизмы СКД или хранилище значений.

Таким образом, использование КомпоновщикНастроекКомпоновкиДанных в связке с макетом СКД является мощным и гибким инструментом для создания пользовательского отбора в произвольных обработках на управляемых формах 1С:Предприятие 8.3. Мы рассмотрели подробные шаги по его реализации, что позволит вам значительно улучшить удобство использования ваших разработок.

← На главную