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