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