Как организовать множественный выбор документов в обработке на обычных формах 1С?

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

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

В чем заключается проблема стандартного поля ввода?

Когда мы размещаем на обычной форме стандартный элемент управления ПолеВвода и связываем его с реквизитом, имеющим тип ссылки на документ (например, ДокументСсылка.РеализацияТоваровУслуг), платформа ожидает выбора строго одного значения. При включении режима множественного выбора форма списка возвращает не ссылку, а коллекцию типа Массив. В результате попытка поместить массив в реквизит с типом ссылки приводит к игнорированию результата либо к ошибке несоответствия типов.

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

Вариант 1. Использование поля со списком значений и модальный выбор

Выясним причину особенностей поведения реквизита с типом СписокЗначений: если просто привязать к нему поле ввода, платформа по нажатию кнопки выбора откроет собственное диалоговое окно редактирования списка, а не форму журнала документов. Чтобы направить пользователя сразу в форму выбора документов, стандартную обработку события необходимо переопределить в коде.

Разберем по шагам реализацию модального выбора:

  1. Создадим в обработке реквизит с типом СписокЗначений (или строковый реквизит для отображения текстового статуса) и разместим для него элемент ПолеВвода.
  2. В свойствах поля ввода включим флажок КнопкаВыбора.
  3. Создадим обработчик события НачалоВыбора и отключим стандартное действие.
  4. Получим форму выбора нужного документа, включим у нее множественный выбор и откроем модально.

Посмотрим на пример процедуры для события НачалоВыбора:


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

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

Вариант 2. Немодальный выбор через событие «ОбработкаВыбора»

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

Разберем по шагам программный код данного подхода:


Процедура ПолеДокументовНачалоВыбора(Элемент, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    ФормаВыбора = Документы.РеализацияТоваровУслуг.ПолучитьФормуВыбора(, Элемент);
    ФормаВыбора.МножественныйВыбор = Истина;
    ФормаВыбора.Открыть();

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

Процедура ПолеДокументовОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    Если ТипЗнч(ВыбранноеЗначение) = Тип("Массив") Тогда
        РеквизитСписокДокументов.Очистить();
        РеквизитСписокДокументов.ЗагрузитьЗначения(ВыбранноеЗначение);
        Элемент.Значение = "Выбрано документов: " + Строка(ВыбранноеЗначение.Количество());
    КонецЕсли;

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

Вариант 3. Использование табличного поля на форме

Проанализируем ситуацию с точки зрения эргономики интерфейса. Одиночное поле ввода, даже содержащее надпись «Выбрано документов: N», не позволяет пользователю наглядно увидеть, какие конкретно накладные были отмечены, и удалить случайный документ без повторного открытия окна подбора.

В таких случаях практичнее разместить на форме элемент управления ТабличноеПоле, источником данных для которого выступает табличная часть обработки или реквизит с типом ТаблицаЗначений (с колонкой Документ). В командной панели таблицы создается кнопка «Подбор», по нажатию которой открывается форма списка документов с множественным выбором. Полученный массив документов построчно добавляется в таблицу, где пользователь может визуально проверять и при необходимости удалять ненужные строки.

Оптимальное заполнение табличной части данными из выбранных документов

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

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


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

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

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

← На главную