Как отобрать документы в форме выбора 1С с помощью запроса?

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

Когда возникает необходимость показать пользователю форму выбора документов, отфильтрованных по определенным условиям, которые можно получить только с помощью запроса к базе данных (например, из регистра накопления), стандартные механизмы отбора могут оказаться недостаточными. Особенно это актуально, когда реквизит имеет составной тип, и перед выбором нужно сначала определить, документ какого типа мы хотим отобрать.

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

Общий подход к решению задачи

Для решения поставленной задачи мы будем действовать по следующему алгоритму:

  1. Перехватим событие начала выбора реквизита, чтобы предотвратить стандартное открытие формы выбора.
  2. Предложим пользователю выбрать конкретный тип документа из составного типа, для которого будет производиться выбор.
  3. На основании выбранного типа документа выполним запрос на сервере, чтобы получить список ссылок на документы, соответствующие нашим критериям (например, из регистра накопления).
  4. Сформируем объект НастройкиКомпоновкиДанных, который будет содержать наш программный отбор по списку ссылок.
  5. Откроем форму выбора для выбранного типа документа, передав ей сформированные настройки отбора в параметрах.
  6. Обработаем результат выбора из формы.

Давайте разберем каждый шаг более детально.

Шаг 1: Инициация выбора и определение типа документа

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


&НаКлиенте
Процедура Расш1_ТоварыХх_ПартияНачалоВыбораПосле(Элемент, ДанныеВыбора, СтандартнаяОбработка)

    // Предотвращаем стандартную обработку выбора
    СтандартнаяОбработка = Ложь; 

    СписокТипов = Новый СписокЗначений;
    СписокТипов.Добавить(Тип("ДокументСсылка.ПриобретениеТоваровУслуг"));
    СписокТипов.Добавить(Тип("ДокументСсылка.ОприходованиеИзлишковТоваров"));

    Оповещение = Новый ОписаниеОповещения("ОбработкаВыбораТипаДанных", ЭтотОбъект);
    СписокТипов.ПоказатьВыборЭлемента(Оповещение, "Выбор типа данных");

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

В этом коде мы:

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

Шаг 2: Получение списка документов на сервере

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


&НаСервере
Функция ВернутьСписокДокументов(ТипДокумента)

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

    // Выполняем запрос и выгружаем ссылки в массив
    РезультатЗапроса = Запрос.Выполнить();
    МассивДокументов = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка");

    Возврат МассивДокументов;

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

В этой функции мы:

  1. Получаем ТипДокумента, который был выбран пользователем.
  2. Формируем текст запроса. В реальной задаче здесь будет сложный запрос к регистру накопления (например, "ОстаткиПоПартиям"), который выберет нужные документы-регистраторы. Например, мы могли бы выбрать регистраторы, по которым есть остатки по конкретной номенклатуре или складу.
  3. Выполняем запрос с помощью Запрос.Выполнить().
  4. Используем РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка") для получения массива ссылок на документы. Этот массив будет использоваться для программного отбора.

Шаг 3: Формирование фиксированных настроек компоновки данных

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


&НаКлиенте
Процедура ОбработкаВыбораТипаДанных(ВыбранныйЭлемент, СписокПараметров) Экспорт

    Если ВыбранныйЭлемент <> Неопределено Тогда
        ИмяОткрываемойФормы = "";
        МассивДок = Неопределено;

        Если ВыбранныйЭлемент.Значение = Тип("ДокументСсылка.ПриобретениеТоваровУслуг") Тогда
            ИмяОткрываемойФормы = "Документ.ПриобретениеТоваровУслуг.ФормаВыбора";
            МассивДок = ВернутьСписокДокументов(ВыбранныйЭлемент.Значение);
        ИначеЕсли ВыбранныйЭлемент.Значение = Тип("ДокументСсылка.ОприходованиеИзлишковТоваров") Тогда
            ИмяОткрываемойФормы = "Документ.ОприходованиеИзлишковТоваров.ФормаВыбора";
            МассивДок = ВернутьСписокДокументов(ВыбранныйЭлемент.Значение);
        КонецЕсли;

        // Если список документов получен, формируем параметры отбора
        Если МассивДок <> Неопределено И МассивДок.Количество() > 0 Тогда
            НастройкиКомпоновки = Новый НастройкиКомпоновкиДанных;
            ГруппаОтбора = НастройкиКомпоновки.Отбор; // Доступ к корневому элементу отбора

            // Создаем элемент отбора
            ЭлементОтбора = ГруппаОтбора.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
            
            // Указываем, по какому полю будем отбирать. "Ссылка" - это системное поле,
            // которое соответствует ссылке на элемент в динамическом списке.
            ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
            
            // Указываем вид сравнения: "ВСписке" позволяет отбирать по массиву значений.
            ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
            
            // Активируем элемент отбора
            ЭлементОтбора.Использование = Истина;
            
            // Присваиваем массив документов в качестве правого значения отбора
            ЭлементОтбора.ПравоеЗначение = МассивДок;

            // Подготавливаем параметры для открытия формы
            ПараметрыВыбора = Новый Структура;
            ПараметрыВыбора.Вставить("ФиксированныеНастройки", НастройкиКомпоновки);
            ПараметрыВыбора.Вставить("РежимВыбора", Истина); // Форма откроется в режиме выбора
            ПараметрыВыбора.Вставить("МножественныйВыбор", Ложь); // Разрешен только одиночный выбор
            
            Оповещение = Новый ОписаниеОповещения("ОписаниеЗакрытияФормыВыбора", ЭтотОбъект);
            ОткрытьФорму(ИмяОткрываемойФормы, ПараметрыВыбора, ЭтаФорма, , , , Оповещение);

        Иначе
            // Если массив документов пуст или не был получен
            ПоказатьПредупреждение(, "Нет документов для выбора по заданным критериям.");
        КонецЕсли;

    КонецЕсли;

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

В этой процедуре мы:

  1. Определяем ИмяОткрываемойФормы в зависимости от выбранного типа документа. Критически важно указывать имя формы выбора (.ФормаВыбора), а не форму документа (.ФормаДокумента). В противном случае возникнет ошибка несоответствия типов, так как формы документа не предназначены для принятия параметров отбора через НастройкиКомпоновкиДанных.
  2. Вызываем нашу серверную функцию ВернутьСписокДокументов() для получения массива ссылок.
  3. Создаем новый объект НастройкиКомпоновкиДанных.
  4. Получаем корневой элемент отбора через НастройкиКомпоновки.Отбор.
  5. Добавляем новый ЭлементОтбораКомпоновкиДанных в коллекцию элементов отбора.
  6. Устанавливаем ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка"). Это указывает системе, что мы будем отбирать по полю "Ссылка", которое является ключевым полем для любого элемента в динамическом списке (документа, справочника).
  7. Устанавливаем ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке. Это означает, что поле "Ссылка" должно присутствовать в списке значений, который мы укажем.
  8. Активируем элемент отбора: ЭлементОтбора.Использование = Истина;.
  9. Присваиваем наш МассивДок, полученный запросом, свойству ЭлементОтбора.ПравоеЗначение. Теперь отбор будет работать по принципу "Ссылка В МассивДок".
  10. Создаем Структура под названием ПараметрыВыбора. В нее мы добавляем следующие ключи:
    • "ФиксированныеНастройки": Присваиваем ей наши сконфигурированные НастройкиКомпоновки. Это главный способ передачи программного отбора в формы, основанные на динамических списках.
    • "РежимВыбора": Устанавливаем в Истина. Это указывает форме, что она открывается для выбора элемента, а не просто для просмотра.
    • "МножественныйВыбор": Устанавливаем в Ложь (или Истина, если нужна возможность выбрать несколько документов).
  11. Создаем ОписаниеОповещения для асинхронной обработки результата закрытия формы выбора.
  12. Открываем форму выбора с помощью ОткрытьФорму(), передавая ей имя формы, наши ПараметрыВыбора и ОписаниеОповещения.

Шаг 4: Обработка результата выбора

После того как пользователь выбрал документ и закрыл форму выбора, результат будет передан в процедуру-обработчик, указанную в ОписаниеОповещения.


&НаКлиенте
Процедура ОписаниеЗакрытияФормыВыбора(РезультатЗакрытия, ДополнительныеПараметры) Экспорт

    Если РезультатЗакрытия <> Неопределено Тогда
        // Присваиваем выбранный документ реквизиту табличной части
        Элементы.Товары.ТекущиеДанные.Хх_Партия = РезультатЗакрытия;
    КонецЕсли;

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

В этой процедуре мы просто проверяем, что РезультатЗакрытия не Неопределено (то есть пользователь что-то выбрал, а не просто закрыл форму), и присваиваем выбранное значение соответствующему реквизиту табличной части.

Важные моменты и частые ошибки

  1. СтандартнаяОбработка = Ложь;: Всегда используйте эту строку при перехвате событий начала выбора, чтобы избежать двойного открытия форм или нежелательного поведения системы.
  2. &НаСервере для запросов: Любая работа с базой данных (выполнение запросов, чтение объектов) должна происходить в серверном контексте. Не забывайте помечать такие функции директивой &НаСервере.
  3. Правильное имя формы: Одна из наиболее распространенных ошибок – попытка открыть Документ.<ИмяДокумента>.ФормаДокумента вместо Документ.<ИмяДокумента>.ФормаВыбора или .ФормаСписка. Параметры ФиксированныеНастройки предназначены для динамических списков, которые используются в формах выбора и списка. Форма документа их не обрабатывает, что приводит к ошибке несоответствия типов.
  4. ПолеКомпоновкиДанных("Ссылка"): Это универсальный способ отбора по ссылке на объект в динамическом списке, будь то документ, справочник или другой объект.
  5. Асинхронность: Метод ОткрытьФорму() в управляемых формах является асинхронным. Это означает, что выполнение кода продолжается сразу после вызова ОткрытьФорму(), а результат выбора обрабатывается только после закрытия открытой формы, в процедуре, указанной в ОписаниеОповещения.
  6. Проверка на пустой массив: Перед открытием формы с отбором по списку ссылок рекомендуется проверить, что полученный массив не пуст. Если массив пуст, то форма откроется пустой, что может быть неинформативно для пользователя. В нашем примере мы добавили ПоказатьПредупреждение().

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

← На главную