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