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