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